Linux arm 启动 c语言部分详解第二讲Start kernel setupa.docx

上传人:b****2 文档编号:1991039 上传时间:2023-05-02 格式:DOCX 页数:8 大小:18.62KB
下载 相关 举报
Linux arm 启动 c语言部分详解第二讲Start kernel setupa.docx_第1页
第1页 / 共8页
Linux arm 启动 c语言部分详解第二讲Start kernel setupa.docx_第2页
第2页 / 共8页
Linux arm 启动 c语言部分详解第二讲Start kernel setupa.docx_第3页
第3页 / 共8页
Linux arm 启动 c语言部分详解第二讲Start kernel setupa.docx_第4页
第4页 / 共8页
Linux arm 启动 c语言部分详解第二讲Start kernel setupa.docx_第5页
第5页 / 共8页
Linux arm 启动 c语言部分详解第二讲Start kernel setupa.docx_第6页
第6页 / 共8页
Linux arm 启动 c语言部分详解第二讲Start kernel setupa.docx_第7页
第7页 / 共8页
Linux arm 启动 c语言部分详解第二讲Start kernel setupa.docx_第8页
第8页 / 共8页
亲,该文档总共8页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

Linux arm 启动 c语言部分详解第二讲Start kernel setupa.docx

《Linux arm 启动 c语言部分详解第二讲Start kernel setupa.docx》由会员分享,可在线阅读,更多相关《Linux arm 启动 c语言部分详解第二讲Start kernel setupa.docx(8页珍藏版)》请在冰点文库上搜索。

Linux arm 启动 c语言部分详解第二讲Start kernel setupa.docx

Linuxarm启动c语言部分详解第二讲Startkernelsetupa

[原创]Linuxarm启动c语言部分详解第二讲(Startkernel->setup_a

Writtenbyleeming这一讲是主要讲setup_arch中那个没有解释的函数解释完毕,完成setup_arch的函数,好让我们的start_kernel继续下去。

/**paging_init()setsupthepagetables,initialisesthezonememory*maps,andsetsupthezeropage,badpageandbadpagetables.*这部分的主要工作建立页表,初始化内存。

*/void__initpaging_init(structmeminfo*mi,structmachine_desc*mdesc){    void*zero_page;//这个函数主要是用来建立各种类型的页表选项(比如内存是MEMORY类型,设备室DEVICE,中断向量表是HIGH_VECTORS)    build_mem_type_table();{    structcachepolicy*cp;    //获取cp15处理器的c1寄存器位    unsignedintcr=get_cr();    unsignedintuser_pgprot,kern_pgprot;    //获取处理器架构版本    intcpu_arch=cpu_architecture();    inti;    //根据处理器版本号调整cache政策,不是写缓冲区的政策#ifdefined(CONFIG_CPU_DCACHE_DISABLE)    if(cachepolicy>CPOLICY_BUFFERED)          cachepolicy=CPOLICY_BUFFERED;#elifdefined(CONFIG_CPU_DCACHE_WRITETHROUGH)    if(cachepolicy>CPOLICY_WRITETHROUGH)          cachepolicy=CPOLICY_WRITETHROUGH;#endif    if(cpu_arch          if(cachepolicy>=CPOLICY_WRITEALLOC)              cachepolicy=CPOLICY_WRITEBACK;          ecc_mask=0;//因为v5前的处理器的一级描述符没有定义第9位作为保护标志位    }    if(cpu_arch          //mem_types是一个全局数组arch/arm/mm-armv.c,里面有所有类型          for(i=0;i              //prot_l1prot_sect都是一级描述符的意思              //将一级描述符的第4位置1              if(mem_types.prot_l1)                  mem_types.prot_l1|=PMD_BIT4;              if(mem_types.prot_sect)                  mem_types.prot_sect|=PMD_BIT4;          }    }    //我们的cachepolicy是3,因此相应的配置如下    //    .policy      ="writeback",    //    .cr_mask    =0,    //    .pmd        =PMD_SECT_WB,    //    .pte      =PTE_BUFFERABLE|PTE_CACHEABLE,    cp=&cache_policies[cachepolicy];    //kern_pgprotuser_pgprot是内核和用户空间的二级页表描述符    kern_pgprot=user_pgprot=cp->pte;    //以下删除了非v4t架构的高版本代码    for(i=0;i          //这里依次获取16个默认的保护类型的值          unsignedlongv=pgprot_val(protection_map);          //(L_PTE_BUFFERABLE|L_PTE_CACHEABLE)这是linuxpte的定义          //内核中有linux和hardware两种定义方式,为了更好的兼容性          //这里两者间是匹配的,这里将值再加上我们的设置就是          //最新的16个值,将它写回更新          v=(v&~(L_PTE_BUFFERABLE|L_PTE_CACHEABLE))|user_pgprot;          protection_map=__pgprot(v);    }    mem_types[MT_LOW_VECTORS].prot_pte|=kern_pgprot;    mem_types[MT_HIGH_VECTORS].prot_pte|=kern_pgprot;    mem_types[MT_MINICLEAN].prot_sect&=~PMD_SECT_TEX

(1);    pgprot_kernel=__pgprot(L_PTE_PRESENT|L_PTE_YOUNG|                    L_PTE_DIRTY|L_PTE_WRITE|                    L_PTE_EXEC|kern_pgprot);    mem_types[MT_LOW_VECTORS].prot_l1|=ecc_mask;    mem_types[MT_HIGH_VECTORS].prot_l1|=ecc_mask;    mem_types[MT_MEMORY].prot_sect|=ecc_mask|cp->pmd;    mem_types[MT_ROM].prot_sect|=cp->pmd;    switch(cp->pmd){    casePMD_SECT_WT:

          mem_types[MT_CACHECLEAN].prot_sect|=PMD_SECT_WT;          break;    casePMD_SECT_WB:

    casePMD_SECT_WBWA:

          mem_types[MT_CACHECLEAN].prot_sect|=PMD_SECT_WB;          break;    }    //以上所有的操作都是为了给mem_types这个结构体中的各种类型中的页表参数添加上我们的要求,主要是一级页表,二级页表,ap(访问权限控制);至于domain是利用系统初始化时的值,不用我们再进行干预。

//系统的domain类型一共有四种,kernel——0;user——1;io——2    printk("Memorypolicy:

ECC%sabled,Datacache%s\n",          ecc_mask?

"en":

"dis",cp->policy);}    bootmem_init(mi);{          unsignedlongaddr,memend_pfn=0;    intnode,initrd_node,i;    /*      *Invalidatethenodenumberforemptyorinvalidmemorybanks      */    for(i=0;inr_banks;i++)          if(mi->bank.size==0||mi->bank.node>=MAX_NUMNODES)              mi->bank.node=-1;    //将在4020.cfixup函数中定义的内存信息添加到meminfo结构体中    memcpy(&meminfo,mi,sizeof(meminfo));    //MODULE_START是0xc0000000-16M;以2M为单位,清除内核空间一下的用户空间    for(addr=0;addr//内核在进入保护模式前,还没有启用分页功能,在这之前内核要先建立一个临时内核页表,因为在进入保护模式后,内核继续初始化直到建//立完整的内存映射机制之前,仍然需要用到页表来映射相应的内存地址。

临时页表的初始化是在arch/i386/kernel/head.S中进行的:

//swapper_pg_dir是临时页全局目录表,它是在内核编译过程中静态初始化的.//pg0是第一个页表开始的地方,它也是内核编译过程中静态初始化的.//pmd_off_k是获取虚拟地址为addr的页表项地址//pmd_clear是将()中的页表项地址中的数据清0    pmd_clear(pmd_off_k(addr));    #ifdefCONFIG_XIP_KERNEL    /*TheXIPkernelismappedinthemodulearea--skipoverit*/    addr=((unsignedlong)&_etext+PGDIR_SIZE-1)&PGDIR_MASK;#endif    //防止xip之后会有变化,检查,做一次用户空间的清除    for(;addr          pmd_clear(pmd_off_k(addr));    /*      *Clearoutallthekernelspacemappings,exceptforthefirst      *memorybank,uptotheendofthevmallocregion.      */      //清除内核空间,但是不清楚内存所在区域,也就是      //0xc2000000-0xd0000000的空间    for(addr=__phys_to_virt(mi->bank[0].start+mi->bank[0].size);        addr          pmd_clear(pmd_off_k(addr));    /*      *Locatewhichnodecontainstheramdiskimage,ifany.      */      //返回如果有initrd所在的内存节点    initrd_node=check_initrd(mi);    /*      *Runthrougheachnodeinitialisingthebootmemallocator.      */    for_each_node(node){          unsignedlongend_pfn;          //为内存建立一级页表(多的话还有二级页表)          end_pfn=bootmem_init_node(node,initrd_node,mi);          /*          *RememberthehighestmemoryPFN.          */          if(end_pfn>memend_pfn)              memend_pfn=end_pfn;    }   &n

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 医药卫生 > 基础医学

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2