⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tlb.c

📁 这是Skyeye 0.9 版本的源代码
💻 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 + -