Linux内存分析(3) -- create_mapping

在start_kernel对内存的初始化中,会调用arch_setup对平台进行初始化。在该函数中,为创建一级页表,有这样的调用顺序:bootmem_init() --> bootmem_init_node() ->map_memory_bank() --> create_mapping()。

 

create_mapping函数的开始是一系列的检查,有意义的代码是最后的这个循环:

       pgd = pgd_offset_k(addr);            //一级数组中addr对应的段在init_mm->pgd的下标

       end = addr + length;                    //计算结束地址

       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);             //下一段,地址不等于结束地址

 

可见,核心函数是alloc_init_section:

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);           //直接将pdgpmd

 

       //addr, end, phys都是1M对齐,则直接进行段映射(大部分情况下应该是满足条件)

       if (((addr | end | phys) & ~SECTION_MASK) == 0) {

              pmd_t    *p = pmd;

 

              if (addr & SECTION_SIZE)

                     pmd++;          //奇数段(段的处理总是2段一起处理的)

 

              do {

                     //物理地址 | 段属性à填充进段描述符中。(2410规格书P560

                     *pmd = __pmd(phys | type->prot_sect);             

                     phys += SECTION_SIZE;                          //下一段(1M)

              } while (pmd++, addr += SECTION_SIZE, addr != end);

              //这个循环只运行一次

 

              flush_pmd_entry(p);             //同步数据进RAM(由于有cache机制,所以数据操作的时候是先保存在cache中的,这里是强制将数据从cache中刷进RAM)

       } else {

       //没有按1M对齐,直接初始化二级页表。

              //由于这个函数实际是调用不到的,所以这里我们就不做分析了。

              alloc_init_pte(pmd, addr, end, __phys_to_pfn(phys), type);

       }

}

 

小结:

在系统初始化的时候,会开辟内存的前16K空间来保存一级页表数组(内存一共4G,每个段为1M,共4K个段,由于ARM是32位的,所以字长为4个字节,所以保存这4K个段就需要16K内存)。

在看create_map之前,我们需要下看一下S3C2410的规格书中MMU部分一级页表的说明,我们可以知道:

1、高10位为段地址

2、19..12位未用

3、11..0 为一级页表的描述属性。

 

而create_map函数实际上就是根据参数指定的内存类型,将段和其属性合成为一级页表的描述符,然后保存到前16K的管理数组中。

 

可见,create_map和MMU其实并不神秘。

你可能感兴趣的:(c,linux,struct,cache,平台)