免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1896 | 回复: 0
打印 上一主题 下一主题

[原创]Linux arm 启动 c语言部分详解第三讲(Paging_init中重要函数附录) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-12-11 20:41 |只看该作者 |倒序浏览

Written by leeming
Paging_init中重要函数附录:
由于阅读直观起见,在paging_init函数中只是放了一次嵌套的代码,并没有继续嵌套代码,但是还有一个函数对于我们来说也是非常重要的,它就是在bootmem_init(mi); devicemaps_init(mdesc);这两个函数中都涉及的create_mapping,它也是创建页表的直接操作者。
1.void __init create_mapping(struct map_desc *md)
{
       unsigned long virt, length;
       int prot_sect, prot_l1, domain;
       pgprot_t prot_pte;
       unsigned long off = (u32)__pfn_to_phys(md->pfn);
       //只有虚拟地址处于用户空间(只能是中断向量表)
       //但又不是映射为0地址的中断向量表时报错
       //只能给系统空间 或者 中断向量 所在的空间创建映射,绝对不可给用户虚拟空间创建映射。
       if (md->virtual != vectors_base() && md->virtual
              printk(KERN_WARNING "BUG: not creating mapping for "
                     "0x%08llx at 0x%08lx in user region\n",
                     __pfn_to_phys((u64)md->pfn), md->virtual);
              return;
       }
       //当类型为MT_DEVICE或者MT_ROM,但是他们的虚拟地址
       //又处于vmalloc的空间(c0000000----d0000000)
       //VMALLOC_END是在我们include/asm-arm/arch-sep4020/vmalloc.h中定义
       //所以我们在对寄存器进行静态映射其实也是有限制的
       if ((md->type == MT_DEVICE || md->type == MT_ROM) &&
           md->virtual >= PAGE_OFFSET && md->virtual
              printk(KERN_WARNING "BUG: mapping for 0x%08llx at 0x%08lx "
                     "overlaps vmalloc space\n",
                     __pfn_to_phys((u64)md->pfn), md->virtual);
       }

       //获取相应类型的页表项参数,具体的参见paging_init
       //函数中的build_mem_type_table()函数
       domain    = mem_types[md->type].domain;
       prot_pte  = __pgprot(mem_types[md->type].prot_pte);
//这里的domain只是说明了我这一段空间是属于16个域中的哪个域
//并没有对域的权限做限定,系统其实就用了几个域:内核0,用户1,io3,好像还有个table(页表域),对这几个域的设定(协处理器的c3配置)已经在系统启动的时候head.s中已经完成。
//系统对这段内存进行访问时会通过ap的值(系统会根据linux ap的配置对hardware进行配置),c1寄存器s,r的值,以及所属域来做出访问权限的限制
       prot_l1   = mem_types[md->type].prot_l1 | PMD_DOMAIN(domain);
       prot_sect = mem_types[md->type].prot_sect | PMD_DOMAIN(domain);

       /*
        * Catch 36-bit addresses
        */
        //以下已经超出普通嵌入式应用,忽略
       if(md->pfn >= 0x100000) {
              if(domain) {
                     printk(KERN_ERR "MM: invalid domain in supersection "
                            "mapping for 0x%08llx at 0x%08lx\n",
                            __pfn_to_phys((u64)md->pfn), md->virtual);
                     return;
              }
              if((md->virtual | md->length | __pfn_to_phys(md->pfn))
                     & ~SUPERSECTION_MASK) {
                     printk(KERN_ERR "MM: cannot create mapping for "
                            "0x%08llx at 0x%08lx invalid alignment\n",
                            __pfn_to_phys((u64)md->pfn), md->virtual);
                     return;
              }

              /*
               * Shift bits [35:32] of address into bits [23:20] of PMD
               * (See ARMv6 spec).
               */
              off |= (((md->pfn >> (32 - PAGE_SHIFT)) & 0xF)
       }

       virt   = md->virtual;
       off   -= virt;
       length = md->length;

       //不是合法的一级描述符,并且虚拟地址,偏移量,长度 有不是1M对齐的,就不能进行映射了(创建页表)。
       if (mem_types[md->type].prot_l1 == 0 &&
           (virt & 0xfffff || (virt + off) & 0xfffff || (virt + length) & 0xfffff)) {
              printk(KERN_WARNING "BUG: map for 0x%08lx at 0x%08lx can not "
                     "be mapped using pages, ignoring.\n",
                     __pfn_to_phys(md->pfn), md->virtual);
              return;
       }

       //如果长度不是1 M对齐就需要按页分配
       while ((virt & 0xfffff || (virt + off) & 0xfffff) && length >= PAGE_SIZE) {
              alloc_init_page(virt, virt + off, prot_l1, prot_pte);

              virt   += PAGE_SIZE;
              length -= PAGE_SIZE;
       }

       /*此处删除高版本arm的代码*/

       /*
        * A section mapping covers half a "pgdir" entry.
        */
       while (length >= (PGDIR_SIZE / 2)) {
              //prot_sect是段描述符
              alloc_init_section(virt, virt + off, prot_sect);

              virt   += (PGDIR_SIZE / 2);
              length -= (PGDIR_SIZE / 2);
       }

       //如果大小不是刚好1M,则需要将多余部分进行页映射
       while (length >= PAGE_SIZE) {
              alloc_init_page(virt, virt + off, prot_l1, prot_pte);

              virt   += PAGE_SIZE;
              length -= PAGE_SIZE;
       }
}

2. 关联函数:
alloc_init_section(unsigned long virt, unsigned long phys, int prot)
{
       //pmdp是一级页表描述符的地址
       pmd_t *pmdp = pmd_off_k(virt);

       if (virt & (1
              pmdp++;
       //向一级页表描述符地址中写入一级页表描述符
       //一级页表描述符:12bit phys | 20 bit prot
       //对于内存来说打印信息为: pmdp is c0007000, value is 3000041e
       //                                      pmdp is c000707c, value is 31f0041e
       *pmdp = __pmd(phys | prot);
       flush_pmd_entry(pmdp);
}
alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pgprot_t prot)
{
       pmd_t *pmdp = pmd_off_k(virt);
       pte_t *ptep;

       if (pmd_none(*pmdp)) {
  //对于粗颗粒小页变换,一级页表描述符是和二级页表的基地址有关的
//所以这里除了有protl1还有ptep的物理地址
              ptep = alloc_bootmem_low_pages(2 * PTRS_PER_PTE *
                                          sizeof(pte_t));

              __pmd_populate(pmdp, __pa(ptep) | prot_l1);
       }
       //根据pmd找pte项(ptep用通俗的语言来说就是二级页表描述符地址)
       ptep = pte_offset_kernel(pmdp, virt);

       //ptep是二级页表描述符地址,pfn_pte是根据虚拟地址和配置选项得到二级页表描述符
       //set_pte函数是在arch/arm/mm/proc_720t.s中实现的
       set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, prot));
}
/*
* Function: arm720_set_pte(pte_t *ptep, pte_t pte)
* Params  : r0 = Address to set
*      : r1 = value to set
* Purpose : Set a PTE and flush it out of any WB cache
*/
//其实这一步只是往一个二级页表描述符地址里面存放一个二级页表描述符,一个str指令就能完成的,但正是因为之前所说的在linux中有两种pte机制(linux,硬件),所以在配置完了linux的,还需要配置硬件,因此在这里第一行代码之下,都是为了实现硬件的pte的设置。

              .align     5
ENTRY(cpu_arm720_set_pte)
              str   r1, [r0], #-2048           @ linux version

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

              bic  r2, r1, #PTE_SMALL_AP_MASK
              bic  r2, r2, #PTE_TYPE_MASK
              orr   r2, r2, #PTE_TYPE_SMALL

              tst   r1, #L_PTE_USER                  @ User?
              orrne      r2, r2, #PTE_SMALL_AP_URO_SRW

              tst   r1, #L_PTE_WRITE | L_PTE_DIRTY @ Write and Dirty?
              orreq      r2, r2, #PTE_SMALL_AP_UNO_SRW

              tst   r1, #L_PTE_PRESENT | L_PTE_YOUNG @ Present and Young
              movne   r2, #0

              str   r2, [r0]                 @ hardware version
              mov       pc, lr


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/99423/showart_2118435.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP