forked from eden-emu/eden
added missing skyeye mmu code
This commit is contained in:
parent
56846a4200
commit
9a642caee7
12 changed files with 3333 additions and 44 deletions
307
src/core/arm/interpreter/mmu/tlb.cpp
Normal file
307
src/core/arm/interpreter/mmu/tlb.cpp
Normal file
|
@ -0,0 +1,307 @@
|
|||
#include <assert.h>
|
||||
|
||||
#include "core/arm/interpreter/armdefs.h"
|
||||
|
||||
ARMword tlb_masks[] = {
|
||||
0x00000000, /* TLB_INVALID */
|
||||
0xFFFFF000, /* TLB_SMALLPAGE */
|
||||
0xFFFF0000, /* TLB_LARGEPAGE */
|
||||
0xFFF00000, /* TLB_SECTION */
|
||||
0xFFFFF000, /*TLB_ESMALLPAGE, have TEX attirbute, only for XScale */
|
||||
0xFFFFFC00 /* TLB_TINYPAGE */
|
||||
};
|
||||
|
||||
/* This function encodes table 8-2 Interpreting AP bits,
|
||||
returning non-zero if access is allowed. */
|
||||
static int
|
||||
check_perms (ARMul_State * state, int ap, int read)
|
||||
{
|
||||
int s, r, user;
|
||||
|
||||
s = state->mmu.control & CONTROL_SYSTEM;
|
||||
r = state->mmu.control & CONTROL_ROM;
|
||||
//chy 2006-02-15 , should consider system mode, don't conside 26bit mode
|
||||
user = (state->Mode == USER32MODE) || (state->Mode == USER26MODE) || (state->Mode == SYSTEM32MODE);
|
||||
|
||||
switch (ap) {
|
||||
case 0:
|
||||
return read && ((s && !user) || r);
|
||||
case 1:
|
||||
return !user;
|
||||
case 2:
|
||||
return read || !user;
|
||||
case 3:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
fault_t
|
||||
check_access (ARMul_State * state, ARMword virt_addr, tlb_entry_t * tlb,
|
||||
int read)
|
||||
{
|
||||
int access;
|
||||
|
||||
state->mmu.last_domain = tlb->domain;
|
||||
access = (state->mmu.domain_access_control >> (tlb->domain * 2)) & 3;
|
||||
if ((access == 0) || (access == 2)) {
|
||||
/* It's unclear from the documentation whether this
|
||||
should always raise a section domain fault, or if
|
||||
it should be a page domain fault in the case of an
|
||||
L1 that describes a page table. In the ARM710T
|
||||
datasheets, "Figure 8-9: Sequence for checking faults"
|
||||
seems to indicate the former, while "Table 8-4: Priority
|
||||
encoding of fault status" gives a value for FS[3210] in
|
||||
the event of a domain fault for a page. Hmm. */
|
||||
return SECTION_DOMAIN_FAULT;
|
||||
}
|
||||
if (access == 1) {
|
||||
/* client access - check perms */
|
||||
int subpage, ap;
|
||||
|
||||
switch (tlb->mapping) {
|
||||
/*ks 2004-05-09
|
||||
* only for XScale
|
||||
* Extend Small Page(ESP) Format
|
||||
* 31-12 bits the base addr of ESP
|
||||
* 11-10 bits SBZ
|
||||
* 9-6 bits TEX
|
||||
* 5-4 bits AP
|
||||
* 3 bit C
|
||||
* 2 bit B
|
||||
* 1-0 bits 11
|
||||
* */
|
||||
case TLB_ESMALLPAGE: //xj
|
||||
subpage = 0;
|
||||
//printf("TLB_ESMALLPAGE virt_addr=0x%x \n",virt_addr );
|
||||
break;
|
||||
|
||||
case TLB_TINYPAGE:
|
||||
subpage = 0;
|
||||
//printf("TLB_TINYPAGE virt_addr=0x%x \n",virt_addr );
|
||||
break;
|
||||
|
||||
case TLB_SMALLPAGE:
|
||||
subpage = (virt_addr >> 10) & 3;
|
||||
break;
|
||||
case TLB_LARGEPAGE:
|
||||
subpage = (virt_addr >> 14) & 3;
|
||||
break;
|
||||
case TLB_SECTION:
|
||||
subpage = 3;
|
||||
break;
|
||||
default:
|
||||
assert (0);
|
||||
subpage = 0; /* cleans a warning */
|
||||
}
|
||||
ap = (tlb->perms >> (subpage * 2 + 4)) & 3;
|
||||
if (!check_perms (state, ap, read)) {
|
||||
if (tlb->mapping == TLB_SECTION) {
|
||||
return SECTION_PERMISSION_FAULT;
|
||||
}
|
||||
else {
|
||||
return SUBPAGE_PERMISSION_FAULT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else { /* access == 3 */
|
||||
/* manager access - don't check perms */
|
||||
}
|
||||
return NO_FAULT;
|
||||
}
|
||||
|
||||
fault_t
|
||||
translate (ARMul_State * state, ARMword virt_addr, tlb_s * tlb_t,
|
||||
tlb_entry_t ** tlb)
|
||||
{
|
||||
*tlb = mmu_tlb_search (state, tlb_t, virt_addr);
|
||||
if (!*tlb) {
|
||||
/* walk the translation tables */
|
||||
ARMword l1addr, l1desc;
|
||||
tlb_entry_t entry;
|
||||
|
||||
l1addr = state->mmu.translation_table_base & 0xFFFFC000;
|
||||
l1addr = (l1addr | (virt_addr >> 18)) & ~3;
|
||||
//l1desc = mem_read_word (state, l1addr);
|
||||
bus_read(32, l1addr, &l1desc);
|
||||
switch (l1desc & 3) {
|
||||
case 0:
|
||||
/*
|
||||
* according to Figure 3-9 Sequence for checking faults in arm manual,
|
||||
* section translation fault should be returned here.
|
||||
*/
|
||||
{
|
||||
return SECTION_TRANSLATION_FAULT;
|
||||
}
|
||||
case 3:
|
||||
/* fine page table */
|
||||
// dcl 2006-01-08
|
||||
{
|
||||
ARMword l2addr, l2desc;
|
||||
|
||||
l2addr = l1desc & 0xFFFFF000;
|
||||
l2addr = (l2addr |
|
||||
((virt_addr & 0x000FFC00) >> 8)) &
|
||||
~3;
|
||||
//l2desc = mem_read_word (state, l2addr);
|
||||
bus_read(32, l2addr, &l2desc);
|
||||
|
||||
entry.virt_addr = virt_addr;
|
||||
entry.phys_addr = l2desc;
|
||||
entry.perms = l2desc & 0x00000FFC;
|
||||
entry.domain = (l1desc >> 5) & 0x0000000F;
|
||||
switch (l2desc & 3) {
|
||||
case 0:
|
||||
state->mmu.last_domain = entry.domain;
|
||||
return PAGE_TRANSLATION_FAULT;
|
||||
case 3:
|
||||
entry.mapping = TLB_TINYPAGE;
|
||||
break;
|
||||
case 1:
|
||||
// this is untested
|
||||
entry.mapping = TLB_LARGEPAGE;
|
||||
break;
|
||||
case 2:
|
||||
// this is untested
|
||||
entry.mapping = TLB_SMALLPAGE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
/* coarse page table */
|
||||
{
|
||||
ARMword l2addr, l2desc;
|
||||
|
||||
l2addr = l1desc & 0xFFFFFC00;
|
||||
l2addr = (l2addr |
|
||||
((virt_addr & 0x000FF000) >> 10)) &
|
||||
~3;
|
||||
//l2desc = mem_read_word (state, l2addr);
|
||||
bus_read(32, l2addr, &l2desc);
|
||||
|
||||
entry.virt_addr = virt_addr;
|
||||
entry.phys_addr = l2desc;
|
||||
entry.perms = l2desc & 0x00000FFC;
|
||||
entry.domain = (l1desc >> 5) & 0x0000000F;
|
||||
//printf("SKYEYE:PAGE virt_addr = %x,l1desc=%x,phys_addr=%x\n",virt_addr,l1desc,entry.phys_addr);
|
||||
//chy 2003-09-02 for xscale
|
||||
switch (l2desc & 3) {
|
||||
case 0:
|
||||
state->mmu.last_domain = entry.domain;
|
||||
return PAGE_TRANSLATION_FAULT;
|
||||
case 3:
|
||||
if (!state->is_XScale) {
|
||||
state->mmu.last_domain =
|
||||
entry.domain;
|
||||
return PAGE_TRANSLATION_FAULT;
|
||||
};
|
||||
//ks 2004-05-09 xscale shold use Extend Small Page
|
||||
//entry.mapping = TLB_SMALLPAGE;
|
||||
entry.mapping = TLB_ESMALLPAGE; //xj
|
||||
break;
|
||||
case 1:
|
||||
entry.mapping = TLB_LARGEPAGE;
|
||||
break;
|
||||
case 2:
|
||||
entry.mapping = TLB_SMALLPAGE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
/* section */
|
||||
//printf("SKYEYE:WARNING: not implement section mapping incompletely\n");
|
||||
//printf("SKYEYE:SECTION virt_addr = %x,l1desc=%x\n",virt_addr,l1desc);
|
||||
//return SECTION_DOMAIN_FAULT;
|
||||
//#if 0
|
||||
entry.virt_addr = virt_addr;
|
||||
entry.phys_addr = l1desc;
|
||||
entry.perms = l1desc & 0x00000C0C;
|
||||
entry.domain = (l1desc >> 5) & 0x0000000F;
|
||||
entry.mapping = TLB_SECTION;
|
||||
break;
|
||||
//#endif
|
||||
}
|
||||
entry.virt_addr &= tlb_masks[entry.mapping];
|
||||
entry.phys_addr &= tlb_masks[entry.mapping];
|
||||
|
||||
/* place entry in the tlb */
|
||||
*tlb = &tlb_t->entrys[tlb_t->cycle];
|
||||
tlb_t->cycle = (tlb_t->cycle + 1) % tlb_t->num;
|
||||
**tlb = entry;
|
||||
}
|
||||
state->mmu.last_domain = (*tlb)->domain;
|
||||
return NO_FAULT;
|
||||
}
|
||||
|
||||
int
|
||||
mmu_tlb_init (tlb_s * tlb_t, int num)
|
||||
{
|
||||
tlb_entry_t *e;
|
||||
int i;
|
||||
|
||||
e = (tlb_entry_t *) malloc (sizeof (*e) * num);
|
||||
if (e == NULL) {
|
||||
ERROR_LOG(ARM11, "malloc size %d\n", sizeof (*e) * num);
|
||||
goto tlb_malloc_error;
|
||||
}
|
||||
tlb_t->entrys = e;
|
||||
for (i = 0; i < num; i++, e++)
|
||||
e->mapping = TLB_INVALID;
|
||||
tlb_t->cycle = 0;
|
||||
tlb_t->num = num;
|
||||
return 0;
|
||||
|
||||
tlb_malloc_error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
mmu_tlb_exit (tlb_s * tlb_t)
|
||||
{
|
||||
free (tlb_t->entrys);
|
||||
};
|
||||
|
||||
void
|
||||
mmu_tlb_invalidate_all (ARMul_State * state, tlb_s * tlb_t)
|
||||
{
|
||||
int entry;
|
||||
|
||||
for (entry = 0; entry < tlb_t->num; entry++) {
|
||||
tlb_t->entrys[entry].mapping = TLB_INVALID;
|
||||
}
|
||||
tlb_t->cycle = 0;
|
||||
}
|
||||
|
||||
void
|
||||
mmu_tlb_invalidate_entry (ARMul_State * state, tlb_s * tlb_t, ARMword addr)
|
||||
{
|
||||
tlb_entry_t *tlb;
|
||||
|
||||
tlb = mmu_tlb_search (state, tlb_t, addr);
|
||||
if (tlb) {
|
||||
tlb->mapping = TLB_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
tlb_entry_t *
|
||||
mmu_tlb_search (ARMul_State * state, tlb_s * tlb_t, ARMword virt_addr)
|
||||
{
|
||||
int entry;
|
||||
|
||||
for (entry = 0; entry < tlb_t->num; entry++) {
|
||||
tlb_entry_t *tlb;
|
||||
ARMword mask;
|
||||
|
||||
tlb = &(tlb_t->entrys[entry]);
|
||||
if (tlb->mapping == TLB_INVALID) {
|
||||
continue;
|
||||
}
|
||||
mask = tlb_masks[tlb->mapping];
|
||||
if ((virt_addr & mask) == (tlb->virt_addr & mask)) {
|
||||
return tlb;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue