Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1685837
  • 博文数量: 511
  • 博客积分: 967
  • 博客等级: 准尉
  • 技术积分: 2560
  • 用 户 组: 普通用户
  • 注册时间: 2012-07-06 14:19
文章分类

全部博文(511)

文章存档

2016年(11)

2015年(61)

2014年(257)

2013年(63)

2012年(119)

分类: LINUX

2014-12-08 14:16:39

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 < TASK_SIZE) {

              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 < VMALLOC_END) {

              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) << 20);

       }

 

       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 << 20))

              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);

       }

       //根据pmdpte(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

阅读(1618) | 评论(0) | 转发(0) |
0

上一篇:sysfs文件系统

下一篇:Linux内核DMA机制

给主人留下些什么吧!~~