13Linux启动流程.docx

上传人:b****5 文档编号:7308446 上传时间:2023-01-22 格式:DOCX 页数:13 大小:22.68KB
下载 相关 举报
13Linux启动流程.docx_第1页
第1页 / 共13页
13Linux启动流程.docx_第2页
第2页 / 共13页
13Linux启动流程.docx_第3页
第3页 / 共13页
13Linux启动流程.docx_第4页
第4页 / 共13页
13Linux启动流程.docx_第5页
第5页 / 共13页
点击查看更多>>
下载资源
资源描述

13Linux启动流程.docx

《13Linux启动流程.docx》由会员分享,可在线阅读,更多相关《13Linux启动流程.docx(13页珍藏版)》请在冰豆网上搜索。

13Linux启动流程.docx

13Linux启动流程

Linux启动流程

1.Linux2.6.31启动流程分析

1.1.Linux/arch/arm/boot/compressed/head.s

u_boot跳到内核最先执行的代码是linux/arch/arm/boot/compressed/head.S。

这个程序完成的主要工作是解压内核,然后跳转到相关执行地址。

这部分代码在做驱动开发时不需要改动。

1.2.linux/arch/arm/kernel/head.S分析

linux/arch/arm/kernel/head.S用汇编代码完成,是内核最先执行的一个文件。

当解压缩代码执行完后,就开始执行linux/arch/arm/kernel/目录下真正的linux内核代码。

内核链接文件linux/arch/arm/kernel/vmlinux.lds指明:

真正的linux内核代码,开始所处的段空间为.text.head,也即内核代码段的头。

这一段汇编代码的主要作用,是检查cpuid,architecturenumber,初始化页表、cpu、bbs等操作,并跳到start_kernel函数。

这一段汇编代码是linux启动的汇编部分的关键代码段,大致流程为:

寻找CPU类型,查找机器信息,解析内核参数列表,创建内存分页机制,__lookup_processor_type,__lookup_machine_type,__vet_atags函数都在kernel/head-comm.S内,这个文件实际上是被包含在head.S内。

这一段汇编代码在执行前,处理器的状态应满足:

r0-shouldbe0

r1-uniquearchitecturenumber

MMU-off

I-cache-onoroff

D-cache-off

在代码的分析过程中略去一些条件编译的代码。

__INIT

.typestext,%function

ENTRY(stext)/*内核入口点*/

msrcpsr_c,#PSR_F_BIT|PSR_I_BIT|MODE_SVC@ensuresvcmode

@andirqsdisabled/*置当前程序状态寄存器,关中断,svc模式*/

mrcp15,0,r9,c0,c0@getprocessorid/*读processorid到r9*/

bl__lookup_processor_type@r5=procinfor9=cupid/*查找运行的cpu的id值,和此linux编译支持的id值是否有相等*/

movsr10,r5@invalidprocessor(r5=0)?

beq__error_p@yes,error'p'

bl__lookup_machine_type@r5=machinfo/*判断体系类型是否支持*/

movsr8,r5@invalidmachine(r5=0)?

beq__error_a@yes,error'a'

bl__vet_atags/*剖析__vet_atags内核参数列表,判断第一个参数类型是不是ATAG_CORE*/

bl__create_page_tables/*创建临时页表,供初始化使用*/

ldrr13,__switch_data@addresstojumptoafter

@mmuhasbeenenabled

adrlr,__enable_mmu@return(PIC)address

addpc,r10,#PROCINFO_INITFUNC

下面分被对于上述的四个函数进行分析:

在文件linux/arch/arm/kernel/head-common.S

一、__lookup_processor_type函数

/*

*ReadprocessorIDregister(CP#15,CR0),andlookupinthelinker-built

*supportedprocessorlist.Notethatwecan'tusetheabsoluteaddresses

*forthe__proc_infolistssincewearen'trunningwiththeMMUon

*(andtherefore,wearenotinthecorrectaddressspace).Wehaveto

*calculatetheoffset.

*

*r9=cpuid

*Returns:

*r3,r4,r6corrupted

*r5=proc_infopointerinphysicaladdressspace

*r9=cpuid(preserved)

*/

.type__lookup_processor_type,%function

__lookup_processor_type:

adrr3,3f/*取标号3的地址*/

ldmdar3,{r5-r7}/*r5:

__proc_info_begin;r6:

__proc_info_end;r7:

标号3的地址*/

subr3,r3,r7@getoffsetbetweenvirt&phys/*由于adrr3,3f取得标号3的物理地址,此时r7是标号3的虚拟地址,通过此指令获得virt&phys的差值,此时为负值*/

addr5,r5,r3@convertvirtaddressesto

addr6,r6,r3@physicaladdressspace

/*把标号__proc_info_begin,__proc_info_end从虚拟地址转化为物理地址,由于此时mmu没有开启,所以必须以物理地址来进行访问内存*/

1:

ldmiar5,{r3,r4}@value,mask/*从proc_info_list获得cpu_val(r3)和cpu_mask(r4)*/

andr4,r4,r9@maskwantedbits

teqr3,r4/*r9为从cp15读出来的cpuid,判断linux是否支持*/

beq2f/*相等则退出,r5为匹配proc_info的物理地址,

否则在下一个proc_info_list中查找*/

addr5,r5,#PROC_INFO_SZ@sizeof(proc_info_list)

cmpr5,r6

blo1b

movr5,#0@unknownprocessor/*没有找到匹配的,返回r5=0*/

2:

movpc,lr

/****************************************************************************/

/*

*Lookininclude/asm-arm/procinfo.handarch/arm/kernel/arch.[ch]for

*moreinformationaboutthe__proc_infoand__arch_infostructures.

*/

.long__proc_info_begin

.long__proc_info_end

3:

.long.

.long__arch_info_begin

.long__arch_info_end

标号__proc_info_begin__proc_info_end由链接脚本vmlinux.lds.S定义,在进行链接时会把其中内容填充。

__proc_info_begin=.;

*(.proc.info.init)

__proc_info_end=.;

__arch_info_begin=.;

*(.arch.info.init)

__arch_info_end=.;

二、__lookup_machine_type函数

/*

*Lookupmachinearchitectureinthelinker-buildlistofarchitectures.

*Notethatwecan'tusetheabsoluteaddressesforthe__arch_info

*listssincewearen'trunningwiththeMMUon(andtherefore,weare

*notinthecorrectaddressspace).Wehavetocalculatetheoffset.

*

*r1=machinearchitecturenumber

*Returns:

*r3,r4,r6corrupted

*r5=mach_infopointerinphysicaladdressspace

*/

.type__lookup_machine_type,%function

__lookup_machine_type:

/*此函数的实现同__lookup_processor_type,分析略*/

adrr3,3b

ldmiar3,{r4,r5,r6}

subr3,r3,r4@getoffsetbetweenvirt&phys

addr5,r5,r3@convertvirtaddressesto

addr6,r6,r3@physicaladdressspace

1:

ldrr3,[r5,#MACHINFO_TYPE]@getmachinetype

teqr3,r1@matchesloadernumber?

beq2f@found

addr5,r5,#SIZEOF_MACHINE_DESC@nextmachine_desc

cmpr5,r6

blo1b

movr5,#0@unknownmachine

2:

movpc,lr

3、__vet_atags函数

内核参数列表一般放在内核前面16K地址空间处。

列表的表项由structtag构成,每个structtag有常见的以下类型:

ATAG_CORE、ATAG_MEM、ATAG_CMDLINE、ATAG_RAMDISK、ATAG_INITRD等。

这些类型是宏定义,比如#defineATAG_CORE0x54410001

arch/arm/include/asm/setup.h

structtag_header{

__u32size;

__u32tag;

};

structtag{

structtag_headerhdr;

union{

structtag_corecore;//有效的内核

structtag_mem32mem;

structtag_videotextvideotext;

structtag_ramdiskramdisk;//文件系统

structtag_initrdinitrd;//临时根文件系统

structtag_serialnrserialnr;

structtag_revisionrevision;

structtag_videolfbvideolfb;

structtag_cmdlinecmdline;//命令行

}u;

};

/*Determinevalidityofther2atagspointer.Theheuristicrequires

*thatthepointerbealigned,inthefirst16kofphysicalRAMand

*thattheATAG_COREmarkerisfirstandpresent.Futurerevisions

*ofthisfunctionmaybemorelenientwiththephysicaladdressand

*mayalsobeabletomovetheATAGSblockifnecessary.

*

*r8=machinfo

*

*Returns:

*r2eithervalidatagspointer,orzero

*r5,r6corrupted

*/

__vet_atags:

tstr2,#0x3@aligned?

bne1f

ldrr5,[r2,#0]@isfirsttagATAG_CORE?

subsr5,r5,#ATAG_CORE_SIZE

bne1f

ldrr5,[r2,#4]

ldrr6,=ATAG_CORE

cmpr5,r6

bne1f

movpc,lr@atagpointerisok

四、__create_page_tables函数

本例中__create_page_tables函数在linux/arch/arm/kernel/head.S中。

/*

*Setuptheinitialpagetables.Weonlysetupthebarest

*amountwhicharerequiredtogetthekernelrunning,which

*generallymeansmappinginthekernelcode.

*

*r8=machinfo

*r9=cpuid

*r10=procinfo

*

*Returns:

*r0,r3,r6,r7corrupted

*r4=physicalpagetableaddress

*/

.type__create_page_tables,%function

__create_page_tables:

/*假设ram的物理起始地址为0x40000000*/

ldrr5,=PHYS_OFFSET

pgtblr4,r5@pagetableaddress/*r4=0x40004000页表在物理地址中基址*/

/*

*Clearthe16Klevel1swapperpagetable

*/

movr0,r4

movr3,#0

addr6,r0,#0x4000

1:

strr3,[r0],#4/*多条同样的指令在多级流水线体系结构中效率会很高*/

strr3,[r0],#4

strr3,[r0],#4

strr3,[r0],#4

teqr0,r6

bne1b/*把物理地址0x40004000至0x40008000清零*/

ldrr7,[r10,#PROCINFO_MMUFLAGS]@mmuflags

/*

*CreateidentitymappingforfirstMBofkernelto

*caterfortheMMUenable.Thisidentitymapping

*willberemovedbypaging_init().Weuseourcurrentprogram

*countertodeterminecorrespondingsectionbaseaddress.

*/

movr6,pc,lsr#20@startofkernelsection/*r6=0x300*/

orrr3,r7,r6,lsl#20@flags+kernelbase/*r3=0x40000000|muflag=0x40000c1e*/

strr3,[r4,r6,lsl#2]@identitymapping/*0x40004c00中的内容为0x40000c1e*/

/*这一部分把物理地址0x40000000,映射到0x40000000,也就是完全映射,保证了mmu开启,都可以正常取指运行*/

/*

*Nowsetupthepagetablesforourkerneldirect

*mappedregion.

*/

addr0,r4,#(KERNEL_START&0xff000000)>>18

@startofkernel/*r0=0x40007000*/

strr3,[r0,#(KERNEL_START&0x00f00000)>>18]!

/*0x40007000中的内容为0x40000c1e*/

ldrr6,=(KERNEL_END-1)

addr0,r0,#4

addr6,r4,r6,lsr#18

1:

cmpr0,r6

addr3,r3,#1<<20

strlsr3,[r0],#4

bls1b

/*

*Thenmapfirst1MBoframincaseitcontainsourbootparams.

*/

addr0,r4,#PAGE_OFFSET>>18

orrr6,r7,#PHYS_OFFSET

strr6,[r0]/*r0=0x40007000,r6=0x40000c1e*/

movpc,lr

下面以从虚拟地址0xc0005123到物理地址0x40005123的转换为例来说明mmu和页表共同的工作过程。

cp15的寄存器c2存放页表的基地址0x40004000,0x40004000&0xffffc000|((0xc0005123>>18)&0x3ffc)组成地址0x40007000,以此地址作为一级描述符地址,根据上述映射过程可以得到0x40007000中的内容是0x40000c1e,其中c1e说明是段地址,有读写权限(详见一级描述符格式说明),(0x40000c1e&0xfff00000)|(0xc0005123&0xfffff)的到地址0x4005123,此地址就是虚拟地址0xc0005123对应的物理地址。

/*****************************************************************************/

回到linux/arch/arm/kernel/head.S中

/*

*ThefollowingcallsCPUspecificcodeinapositionindependent

*manner.Seearch/arm/mm/proc-*.Sfordetails.r10=baseof

*xxx_proc_infostructureselectedby__lookup_machine_type

*above.Onreturn,theCPUwillbereadyfortheMMUtobe

*turnedon,andr0willholdtheCPUcontrolregistervalue.

*/

ldrr13,__switch_data@addresstojumptoafter

@mmuhasbeenenabled

adrlr,__enable_mmu@return(PIC)address

addpc,r10,#PROCINFO_INITFUNC/*此命令进行mmu寄存器的初始化可以参照cp15寄存器手册来分析实现的功能,执行完成后,执行函数__enable_mmu*/

/*

*SetupcommonbitsbeforefinallyenablingtheMMU.Essentially

*thisisjustloadingthepagetablepointeranddomainaccess

*registers.

*/

.type__enable_mmu,%function

__enable_mmu:

#ifdefCONFIG_ALIGNMENT_TRAP

orrr0,r0,#CR_A

#else

bicr0,r0,#CR_A

#endif

#ifdefCONFIG_CPU_DCACHE_DISABLE

bicr0,r0,#CR_C

#endif

#ifdefCONFIG_CPU_BPREDICT_DISABLE

bicr0,r0,#CR_Z

#endif

#ifdefCONFIG_CPU_ICACHE_DISABLE

bicr0,r0,#CR_I

#endif

movr5,#(domain_val(DOMAIN_USER,DOMAIN_MANAGER)|\

domain_val(DOMAIN_KERNEL,DOMAIN_MANAGER)|\

domain_val(DOMAIN_TABLE,DOMAIN_MANAGER)|\

domain_val(DOMAIN_IO,DOMAIN_CLIENT))

mcrp15,0,r5,c3,c0,0@loaddomainaccessregister

mcrp15,0,r4,c2,c0,0@loadpagetablepointer

b__turn_mmu_on

/*

*EnabletheMMU.Thiscompletelychangesthestructureofthevisible

*memoryspace.Youwillnotbeabletotraceexecutionthroughthis.

*Ifyouhaveanenquiryaboutthis,*please*checkthelinux-arm-kernel

*mailinglistar

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

当前位置:首页 > 高中教育 > 理化生

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1