create_mapping如何创建内存映射表

1 ARM920T的MMU工作原理

下图显示了MMU地址转化关系

 

一级表项的地址(pmd) = ( (TLB) & (0xFFFFC000) ) + ( (Table Index)<<2 );

注1:TLB(Translate table base),即转换表基地址

注2:由于每个表项占32位(4Bytes),因此(Table Index)<<2

一级表项的内容(*pmd) = ( (pte) & (0xFFFFFC00) ) + prot_l1;

-------------------------------------------------------------------------------------

二级表项的地址(pte) =  ( (pte) & (0xFFFFFC00) )  + ( (L2 table index) <<2 );

二级表项的内容(*pte) = ( (PA) & (0xFFFFF000) ) + prot_pte;

 

 

2 create_mapping分析

//利用该函数可以为物理地址创建内存的静态映射

static void __init create_mapping(struct map_desc *md)
{
     ...  

     pgd = pgd_offset_k(addr);

     //计算pgd的地址(64bits) = ((mm)->pgd+pgd_index(addr))

     //                              = ((mm)->pgd+((addr) >> 21) )

     //pmd地址(32bits)        = ((mm)->pgd+((addr) >> 20) )

     end = addr + length;

     //PGDIR_SIZE=(1UL << PGDIR_SHIFT)=2M

     //一次处理2个连续的一级表项:2*1M = 2M
     do {
            unsigned long next = pgd_addr_end(addr, end);

            alloc_init_section(pgd, addr, next, phys, type);

            phys += next - addr;
            addr = next;
      } while (pgd++, addr != end);
}

 

//尝试使用段映射

static void __init alloc_init_section(pgd_t *pgd, unsigned long addr,
          unsigned long end, unsigned long phys,
          const struct mem_type *type)
{
     pmd_t *pmd = pmd_offset(pgd, addr); //一级表指针

     //pmd地址(32bits)        = ((mm)->pgd+((addr) >> 20) )

     

     /*  当大小和地址1MB对齐时,使用段映射 */
     if (((addr | end | phys) & ~SECTION_MASK) == 0) {
         pmd_t *p = pmd;

         if (addr & SECTION_SIZE)
              pmd++;

         do {
             *pmd = __pmd(phys | type->prot_sect);
             phys += SECTION_SIZE;
         } while (pmd++, addr += SECTION_SIZE, addr != end);

         //2MB,循环2次

         flush_pmd_entry(p);
      } else {
          /*  使用small页映射,必须为二级表分配空间4Kb(1page) */
          alloc_init_pte(pmd, addr, end, __phys_to_pfn(phys), type);
       }
}

 

//small页映射

static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr,
      unsigned long end, unsigned long pfn,
      const struct mem_type *type)
{
     pte_t *pte;  //二级表指针

     

     //当一级表项内容为空时,为二级表项分配空间2*512*4 = 4Kb(1Page)

     if (pmd_none(*pmd)) {
         pte = alloc_bootmem_low_pages(2 * PTRS_PER_PTE * sizeof(pte_t));
          __pmd_populate(pmd, __pa(pte) | type->prot_l1);

         //给一级表项赋值,pmd为指针,指向需赋值的地址

         //pmdp[0] = __pmd(pmdval);
         //pmdp[1] = __pmd(pmdval + 256 * sizeof(pte_t));

 

      }

      pte = pte_offset_kernel(pmd, addr);
      do {
          set_pte_ext(pte, pfn_pte(pfn, __pgprot(type->prot_pte)), 0);
          pfn++;
      } while (pte++, addr += PAGE_SIZE, addr != end);

      //2MB,2Mb/4Kb = 512次(最多)
}

 

 

 

.macro armv3_set_pte_ext wc_disable=1
 str r1, [r0], #-2048  @ linux version  MMU看到的h/w pte0/1

 eor r3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY

 bic r2, r1, #PTE_SMALL_AP_MASK @ keep C, B bits
 bic r2, r2, #PTE_TYPE_MASK
 orr r2, r2, #PTE_TYPE_SMALL

 tst r3, #L_PTE_USER   @ user?
 orrne r2, r2, #PTE_SMALL_AP_URO_SRW  @设置SVC模式为读写,USR模式为READONLY

 tst r3, #L_PTE_WRITE | L_PTE_DIRTY @ write and dirty?
 orreq r2, r2, #PTE_SMALL_AP_UNO_SRW 

设置SVC模式为读写,USR模式为不能读,PTE_SMALL_AP_URO_SRW | PTE_SMALL_AP_UNO_SRW为SVC & USR可读写

#define PAGE_SHARED __pgprot(pgprot_val(pgprot_user) | _L_PTE_READ | \
     L_PTE_WRITE)

#define _L_PTE_READ L_PTE_USER | L_PTE_EXEC

PAGE_SHARED 使用PAGE_SHARE映射的空间USR模式也能进行读写

关于读写的权限,参考ARM V5 reference.pdf  协处理器的C3寄存器和PTE的APx(3~0),PMD的domain参数

 tst r3, #L_PTE_PRESENT | L_PTE_YOUNG @ present and young?
 movne r2, #0

 .if /wc_disable
#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
 tst r2, #PTE_CACHEABLE
 bicne r2, r2, #PTE_BUFFERABLE
#endif
 .endif
 str r2, [r0]   @ hardware version
 .endm

 

3 Linux MMU

#define PTRS_PER_PTE512 { (h/w + s/w )  *  4byte = 4096 }
#define PTRS_PER_PMD 1
#define PTRS_PER_PGD 2048

4 9260EK 内存映射情况

Author: WoodPecker <Pecker.hu@gmail.com>

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值