📄 tlb.c
字号:
#include <assert.h>
#include "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 */
};
/* 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;
user = (state->Mode == USER32MODE) || (state->Mode == USER26MODE);
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_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_t * 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);
switch (l1desc & 3)
{
case 0:
//SBZ
{
return PAGE_TRANSLATION_FAULT;
}
case 3:
//fine page table
printf ("SKYEYE: not implement fine page table mapping");
return PAGE_TRANSLATION_FAULT;
case 1:
/* coarse page table */
{
ARMword l2addr, l2desc;
l2addr = l1desc & 0xFFFFFC00;
l2addr = (l2addr | ((virt_addr & 0x000FF000) >> 10)) & ~3;
l2desc = mem_read_word (state, l2addr);
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_t * tlb_t, int num)
{
tlb_entry_t *e;
int i;
e = (tlb_entry_t *) malloc (sizeof (*e) * num);
if (e == NULL)
{
err_msg ("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_t * tlb_t)
{
free (tlb_t->entrys);
};
void
mmu_tlb_invalidate_all (ARMul_State * state, tlb_t * 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_t * 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_t * 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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -