在线观看av毛片亚洲_伊人久久大香线蕉成人综合网_一级片黄色视频播放_日韩免费86av网址_亚洲av理论在线电影网_一区二区国产免费高清在线观看视频_亚洲国产精品久久99人人更爽_精品少妇人妻久久免费

ARM Linu啟動(dòng)過(guò)程

前言:本站為你精心整理了ARM Linu啟動(dòng)過(guò)程范文,希望能為你的創(chuàng)作提供參考價(jià)值,我們的客服老師可以幫助你提供個(gè)性化的參考范文,歡迎咨詢。

摘要:嵌入式Linux的可移植性使得我們可以在各種電子產(chǎn)品上看到它的身影。對(duì)于不同體系結(jié)構(gòu)的處理器來(lái)說(shuō)Linux的啟動(dòng)過(guò)程也有所不同。本文以S3C2410ARM處理器為例,詳細(xì)分析了系統(tǒng)上電后bootloader的執(zhí)行流程及ARMLinux的啟動(dòng)過(guò)程。

關(guān)鍵詞:ARMLinuxbootloader啟動(dòng)過(guò)程

Abstract:

WecanseeembeddedLinuxinkindsofelectronicproductsbecauseofitsportability.Linux’sstart-upprocedurefordifferentprocessorsisalsodifferent.ThispaperprovidestheanalysisofbootloaderexecutionprocessandLinuxkernelstart-upprocedure-takingtheS3C2410ARMprocessorasexample.

Keywords:ARMLinuxbootloaderstart-upprocedure

1.引言

Linux最初是由瑞典赫爾辛基大學(xué)的學(xué)生LinusTorvalds在1991年開發(fā)出來(lái)的,之后在GNU的支持下,Linux獲得了巨大的發(fā)展。雖然Linux在桌面PC機(jī)上的普及程度遠(yuǎn)不及微軟的Windows操作系統(tǒng),但它的發(fā)展速度之快、用戶數(shù)量的日益增多,也是微軟所不能輕視的。而近些年來(lái)Linux在嵌入式領(lǐng)域的迅猛發(fā)展,更是給Linux注入了新的活力。

一個(gè)嵌入式Linux系統(tǒng)從軟件角度看可以分為四個(gè)部分[1]:引導(dǎo)加載程序(bootloader),

Linux內(nèi)核,文件系統(tǒng),應(yīng)用程序。

其中bootloader是系統(tǒng)啟動(dòng)或復(fù)位以后執(zhí)行的第一段代碼,它主要用來(lái)初始化處理器及外設(shè),然后調(diào)用Linux內(nèi)核。Linux內(nèi)核在完成系統(tǒng)的初始化之后需要掛載某個(gè)文件系統(tǒng)做為根文件系統(tǒng)(RootFilesystem)。根文件系統(tǒng)是Linux系統(tǒng)的核心組成部分,它可以做為L(zhǎng)inux系統(tǒng)中文件和數(shù)據(jù)的存儲(chǔ)區(qū)域,通常它還包括系統(tǒng)配置文件和運(yùn)行應(yīng)用軟件所需要的庫(kù)。應(yīng)用程序可以說(shuō)是嵌入式系統(tǒng)的“靈魂”,它所實(shí)現(xiàn)的功能通常就是設(shè)計(jì)該嵌入式系統(tǒng)所要達(dá)到的目標(biāo)。如果沒(méi)有應(yīng)用程序的支持,任何硬件上設(shè)計(jì)精良的嵌入式系統(tǒng)都沒(méi)有實(shí)用意義。

從以上分析我們可以看出bootloader和Linux內(nèi)核在嵌入式系統(tǒng)中的關(guān)系和作用。Bootloader在運(yùn)行過(guò)程中雖然具有初始化系統(tǒng)和執(zhí)行用戶輸入的命令等作用,但它最根本的功能就是為了啟動(dòng)Linux內(nèi)核。在嵌入式系統(tǒng)開發(fā)的過(guò)程中,很大一部分精力都是花在bootloader和Linux內(nèi)核的開發(fā)或移植上。如果能清楚的了解bootloader執(zhí)行流程和Linux的啟動(dòng)過(guò)程,將有助于明確開發(fā)過(guò)程中所需的工作,從而加速嵌入式系統(tǒng)的開發(fā)過(guò)程。而這正是本文的所要研究的內(nèi)容。

2.Bootloader

2.1Bootloader的概念和作用Bootloader是嵌入式系統(tǒng)的引導(dǎo)加載程序,它是系統(tǒng)上電后運(yùn)行的第一段程序,其作用類似于PC機(jī)上的BIOS。在完成對(duì)系統(tǒng)的初始化任務(wù)之后,它會(huì)將非易失性存儲(chǔ)器(通常是Flash或DOC等)中的Linux內(nèi)核拷貝到RAM中去,然后跳轉(zhuǎn)到內(nèi)核的第一條指令處繼續(xù)執(zhí)行,從而啟動(dòng)Linux內(nèi)核。由此可見,bootloader和Linux內(nèi)核有著密不可分的聯(lián)系,要想清楚的了解Linux內(nèi)核的啟動(dòng)過(guò)程,我們必須先得認(rèn)識(shí)bootloader的執(zhí)行過(guò)程,這樣才能對(duì)嵌入式系統(tǒng)的整個(gè)啟過(guò)程有清晰的掌握。

2.2Bootloader的執(zhí)行過(guò)程不同的處理器上電或復(fù)位后執(zhí)行的第一條指令地址并不相同,對(duì)于ARM處理器來(lái)說(shuō),該地址為0x00000000。對(duì)于一般的嵌入式系統(tǒng),通常把Flash等非易失性存儲(chǔ)器映射到這個(gè)地址處,而bootloader就位于該存儲(chǔ)器的最前端,所以系統(tǒng)上電或復(fù)位后執(zhí)行的第一段程序便是bootloader。而因?yàn)榇鎯?chǔ)bootloader的存儲(chǔ)器不同,bootloader的執(zhí)行過(guò)程也并不相同,下面將具體分析。

嵌入式系統(tǒng)中廣泛采用的非易失性存儲(chǔ)器通常是Flash,而Flash又分為NorFlash和NandFlash兩種。它們之間的不同在于:NorFlash支持芯片內(nèi)執(zhí)行(XIP,eXecuteInPlace),這樣代碼可以在Flash上直接執(zhí)行而不必拷貝到RAM中去執(zhí)行。而NandFlash并不支持XIP,所以要想執(zhí)行NandFlash上的代碼,必須先將其拷貝到RAM中去,然后跳到RAM中去執(zhí)行。實(shí)際應(yīng)用中的bootloader根據(jù)所需功能的不同可以設(shè)計(jì)得很復(fù)雜,除完成基本的初始化系統(tǒng)和調(diào)用Linux內(nèi)核等基本任務(wù)外,還可以執(zhí)行很多用戶輸入的命令,比如設(shè)置Linux啟動(dòng)參數(shù),給Flash分區(qū)等;也可以設(shè)計(jì)得很簡(jiǎn)單,只完成最基本的功能。但為了能達(dá)到啟動(dòng)Linux內(nèi)核的目的,所有的bootloader都必須具備以下功能[2]:

1)初始化RAM

因?yàn)長(zhǎng)inux內(nèi)核一般都會(huì)在RAM中運(yùn)行,所以在調(diào)用Linux內(nèi)核之前bootloader必須設(shè)置和初始化RAM,為調(diào)用Linux內(nèi)核做好準(zhǔn)備。初始化RAM的任務(wù)包括設(shè)置CPU的控制寄存器參數(shù),以便能正常使用RAM以及檢測(cè)RAM大小等。

2)初始化串口串口在Linux的啟動(dòng)過(guò)程中有著非常重要的作用,它是Linux內(nèi)核和用戶交互的方式之一。Linux在啟動(dòng)過(guò)程中可以將信息通過(guò)串口輸出,這樣便可清楚的了解Linux的啟動(dòng)過(guò)程。雖然它并不是bootloader必須要完成的工作,但是通過(guò)串口輸出信息是調(diào)試bootloader和Linux內(nèi)核的強(qiáng)有力的工具,所以一般的bootloader都會(huì)在執(zhí)行過(guò)程中初始化一個(gè)串口做為調(diào)試端口。

3)檢測(cè)處理器類型

Bootloader在調(diào)用Linux內(nèi)核前必須檢測(cè)系統(tǒng)的處理器類型,并將其保存到某個(gè)常量中提供給Linux內(nèi)核。Linux內(nèi)核在啟動(dòng)過(guò)程中會(huì)根據(jù)該處理器類型調(diào)用相應(yīng)的初始化程序。

4)設(shè)置Linux啟動(dòng)參數(shù)

Bootloader在執(zhí)行過(guò)程中必須設(shè)置和初始化Linux的內(nèi)核啟動(dòng)參數(shù)。目前傳遞啟動(dòng)參數(shù)主要采用兩種方式:即通過(guò)structparam_struct和structtag(標(biāo)記列表,taggedlist)兩種結(jié)構(gòu)傳遞。structparam_struct是一種比較老的參數(shù)傳遞方式,在2.4版本以前的內(nèi)核中使用較

多。從2.4版本以后Linux內(nèi)核基本上采用標(biāo)記列表的方式。但為了保持和以前版本的兼容性,它仍支持structparam_struct參數(shù)傳遞方式,只不過(guò)在內(nèi)核啟動(dòng)過(guò)程中它將被轉(zhuǎn)換成標(biāo)記列表方式。

標(biāo)記列表方式是種比較新的參數(shù)傳遞方式,它必須以ATAG_CORE開始,并以ATAG_NONE結(jié)尾。中間可以根據(jù)需要加入其他列表。Linux內(nèi)核在啟動(dòng)過(guò)程中會(huì)根據(jù)該啟動(dòng)參數(shù)進(jìn)行相應(yīng)的初始化工作。

5)調(diào)用Linux內(nèi)核映像

Bootloader完成的最后一項(xiàng)工作便是調(diào)用Linux內(nèi)核。如果Linux內(nèi)核存放在Flash中,并且可直接在上面運(yùn)行(這里的Flash指NorFlash),那么可直接跳轉(zhuǎn)到內(nèi)核中去執(zhí)行。但由于在Flash中執(zhí)行代碼會(huì)有種種限制,而且速度也遠(yuǎn)不及RAM快,所以一般的嵌入式系統(tǒng)都是將Linux內(nèi)核拷貝到RAM中,然后跳轉(zhuǎn)到RAM中去執(zhí)行。不論哪種情況,在跳到Linux內(nèi)核執(zhí)行之前CUP的寄存器必須滿足以下條件:r0=0,r1=處理器類型,r2=標(biāo)記列表在RAM中的地址。

.Linux內(nèi)核的啟動(dòng)過(guò)程

在bootloader將Linux內(nèi)核映像拷貝到RAM以后,可以通過(guò)下例代碼啟動(dòng)Linux內(nèi)核:call_linux(0,machine_type,kernel_params_base)。

其中,machine_tpye是bootloader檢測(cè)出來(lái)的處理器類型,kernel_params_base是啟動(dòng)參數(shù)在RAM的地址。通過(guò)這種方式將Linux啟動(dòng)需要的參數(shù)從bootloader傳遞到內(nèi)核。Linux內(nèi)核有兩種映像:一種是非壓縮內(nèi)核,叫Image,另一種是它的壓縮版本,叫zImage。根據(jù)內(nèi)核映像的不同,Linux內(nèi)核的啟動(dòng)在開始階段也有所不同。zImage是Image經(jīng)過(guò)壓縮形成的,所以它的大小比Image小。但為了能使用zImage,必須在它的開頭加上解壓縮的代碼,將zImage解壓縮之后才能執(zhí)行,因此它的執(zhí)行速度比Image要慢。但考慮到嵌入式系統(tǒng)的存儲(chǔ)空容量一般比較小,采用zImage可以占用較少的存儲(chǔ)空間,因此犧牲一點(diǎn)性能上的代價(jià)也是值得的。所以一般的嵌入式系統(tǒng)均采用壓縮內(nèi)核的方式。

對(duì)于ARM系列處理器來(lái)說(shuō),zImage的入口程序即為arch/arm/boot/compressed/head.S。它依次完成以下工作:開啟MMU和Cache,調(diào)用decompress_kernel()解壓內(nèi)核,最后通過(guò)調(diào)用call_kernel()進(jìn)入非壓縮內(nèi)核Image的啟動(dòng)。下面將具體分析在此之后Linux內(nèi)核的啟動(dòng)過(guò)程。

3.1Linux內(nèi)核入口

Linux非壓縮內(nèi)核的入口位于文件/arch/arm/kernel/head-armv.S中的stext段。該段的基地址就是壓縮內(nèi)核解壓后的跳轉(zhuǎn)地址。如果系統(tǒng)中加載的內(nèi)核是非壓縮的Image,那么bootloader將內(nèi)核從Flash中拷貝到RAM后將直接跳到該地址處,從而啟動(dòng)Linux內(nèi)核。不同體系結(jié)構(gòu)的Linux系統(tǒng)的入口文件是不同的,而且因?yàn)樵撐募c具體體系結(jié)構(gòu)有關(guān),所以一般均用匯編語(yǔ)言編寫[3]。對(duì)基于ARM處理的Linux系統(tǒng)來(lái)說(shuō),該文件就是head-armv.S。該程序通過(guò)查找處理器內(nèi)核類型和處理器類型調(diào)用相應(yīng)的初始化函數(shù),再建立頁(yè)表,最后跳轉(zhuǎn)到start_kernel()函數(shù)開始內(nèi)核的初始化工作。

檢測(cè)處理器內(nèi)核類型是在匯編子函數(shù)__lookup_processor_type中完成的。通過(guò)以下代碼可實(shí)現(xiàn)對(duì)它的調(diào)用:bl__lookup_processor_type。__lookup_processor_type調(diào)用結(jié)束返回原程序時(shí),會(huì)將返回結(jié)果保存到寄存器中。其中r8保存了頁(yè)表的標(biāo)志位,r9保存了處理器的ID號(hào),r10保存了與處理器相關(guān)的struproc_info_list結(jié)構(gòu)地址。

檢測(cè)處理器類型是在匯編子函數(shù)__lookup_architecture_type中完成的。與__lookup_processor_type類似,它通過(guò)代碼:“bl__lookup_processor_type”來(lái)實(shí)現(xiàn)對(duì)它的調(diào)用。該函數(shù)返回時(shí),會(huì)將返回結(jié)構(gòu)保存在r5、r6和r7三個(gè)寄存器中。其中r5保存了RAM的起始基地址,r6保存了I/O基地址,r7保存了I/O的頁(yè)表偏移地址。當(dāng)檢測(cè)處理器內(nèi)核和處理器類型結(jié)束后,將調(diào)用__create_page_tables子函數(shù)來(lái)建立頁(yè)表,它所要做的工作就是將RAM基地址開始的4M空間的物理地址映射到0xC0000000開始的虛擬地址處。對(duì)筆者的S3C2410開發(fā)板而言,RAM連接到物理地址0x30000000處,當(dāng)調(diào)用__create_page_tables結(jié)束后0x30000000~0x30400000物理地址將映射到0xC0000000~0xC0400000虛擬地址處。

當(dāng)所有的初始化結(jié)束之后,使用如下代碼來(lái)跳到C程序的入口函數(shù)start_kernel()處,開始之后的內(nèi)核初始化工作:

bSYMBOL_NAME(start_kernel)

3.2start_kernel函數(shù)

start_kernel是所有Linux平臺(tái)進(jìn)入系統(tǒng)內(nèi)核初始化后的入口函數(shù),它主要完成剩余的與硬件平臺(tái)相關(guān)的初始化工作,在進(jìn)行一系列與內(nèi)核相關(guān)的初始化后,調(diào)用第一個(gè)用戶進(jìn)程-init進(jìn)程并等待用戶進(jìn)程的執(zhí)行,這樣整個(gè)Linux內(nèi)核便啟動(dòng)完畢。該函數(shù)所做的具體工作有[4][5]

1)調(diào)用setup_arch()函數(shù)進(jìn)行與體系結(jié)構(gòu)相關(guān)的第一個(gè)初始化工作;

對(duì)不同的體系結(jié)構(gòu)來(lái)說(shuō)該函數(shù)有不同的定義。對(duì)于ARM平臺(tái)而言,該函數(shù)定義在arch/arm/kernel/Setup.c。它首先通過(guò)檢測(cè)出來(lái)的處理器類型進(jìn)行處理器內(nèi)核的初始化,然后通過(guò)bootmem_init()函數(shù)根據(jù)系統(tǒng)定義的meminfo結(jié)構(gòu)進(jìn)行內(nèi)存結(jié)構(gòu)的初始化,最后調(diào)用paging_init()開啟MMU,創(chuàng)建內(nèi)核頁(yè)表,映射所有的物理內(nèi)存和IO空間。

2)創(chuàng)建異常向量表和初始化中斷處理函數(shù);

3)初始化系統(tǒng)核心進(jìn)程調(diào)度器和時(shí)鐘中斷處理機(jī)制;

4)初始化串口控制臺(tái)(serial-console);

ARM-Linux在初始化過(guò)程中一般都會(huì)初始化一個(gè)串口做為內(nèi)核的控制臺(tái),這樣內(nèi)核在啟動(dòng)過(guò)程中就可以通過(guò)串口輸出信息以便開發(fā)者或用戶了解系統(tǒng)的啟動(dòng)進(jìn)程。

5)創(chuàng)建和初始化系統(tǒng)cache,為各種內(nèi)存調(diào)用機(jī)制提供緩存,包括;動(dòng)態(tài)內(nèi)存分配,虛擬文件系統(tǒng)(VirtualFileSystem)及頁(yè)緩存。

6)初始化內(nèi)存管理,檢測(cè)內(nèi)存大小及被內(nèi)核占用的內(nèi)存情況;

7)初始化系統(tǒng)的進(jìn)程間通信機(jī)制(IPC);

當(dāng)以上所有的初始化工作結(jié)束后,start_kernel()函數(shù)會(huì)調(diào)用rest_init()函數(shù)來(lái)進(jìn)行最后的初始化,包括創(chuàng)建系統(tǒng)的第一個(gè)進(jìn)程-init進(jìn)程來(lái)結(jié)束內(nèi)核的啟動(dòng)。Init進(jìn)程首先進(jìn)行一系列的硬件初始化,然后通過(guò)命令行傳遞過(guò)來(lái)的參數(shù)掛載根文件系統(tǒng)。最后init進(jìn)程會(huì)執(zhí)行用戶傳遞過(guò)來(lái)的“init=”啟動(dòng)參數(shù)執(zhí)行用戶指定的命令,或者執(zhí)行以下幾個(gè)進(jìn)程之一:

execve("/sbin/init",argv_init,envp_init);

execve("/etc/init",argv_init,envp_init);

execve("/bin/init",argv_init,envp_init);

execve("/bin/sh",argv_init,envp_init)。

當(dāng)所有的初始化工作結(jié)束后,cpu_idle()函數(shù)會(huì)被調(diào)用來(lái)使系統(tǒng)處于閑置(idle)狀態(tài)并等待用戶程序的執(zhí)行。至此,整個(gè)Linux內(nèi)核啟動(dòng)完畢。

4.結(jié)論

Linux內(nèi)核是一個(gè)非常龐大的工程,經(jīng)過(guò)十多年的發(fā)展,它已從從最初的幾百KB大小發(fā)展到現(xiàn)在的幾百兆。清晰的了解它執(zhí)行的每一個(gè)過(guò)程是件非常困難的事。但是在嵌入式開發(fā)過(guò)程中,我們并不需要十分清楚linux的內(nèi)部工作機(jī)制,只要適當(dāng)修改linux內(nèi)核中那些與硬件相關(guān)的部分,就可以將linux移植到其它目標(biāo)平臺(tái)上。通過(guò)對(duì)linux的啟動(dòng)過(guò)程的分析,我們可以看出哪些是和硬件相關(guān)的,哪些是linux內(nèi)核內(nèi)部已實(shí)現(xiàn)的功能,這樣在移植linux的過(guò)程中便有所針對(duì)。而linux內(nèi)核的分層設(shè)計(jì)將使linux的移植變得更加容易。

參考文獻(xiàn)

[1]詹榮開.嵌入式系統(tǒng)bootloader技術(shù)內(nèi)幕[EB/OL]./developerworks/cn/linux/l-btloader/index.html,2003.12.

[2]RussellKing.BootingARMLinux[Z].LinuxDocumentation.May2002

[3]劉淼.嵌入式系統(tǒng)接口設(shè)計(jì)與Linux驅(qū)動(dòng)程序開發(fā)[M].北京航空航天大學(xué)出版社.2006.6

[4]WilliamGatliff.TheLinux2.4Kernel’sStartupProcedure[DB/CD].2002EmbeddedSystemConferenceSanFrancisco,March..2002

[5]ClaudiaSalzbergRodriguez,GordonFischer,StevenSmolski.Linux內(nèi)核編程[M].陳莉君,賀炎,劉霞林.機(jī)械工業(yè)出版社.2006.7

平江县| 罗城| 大渡口区| 吕梁市| 阜南县| 三江| 双牌县| 遂川县| 调兵山市| 弥渡县| 乐山市| 乌拉特后旗| 阜新市| 瓮安县| 丰原市| 荆门市| 菏泽市| 尼木县| 叶城县| 治县。| 鄱阳县| 郧西县| 五莲县| 修武县| 长葛市| 平定县| 桓台县| 宾阳县| 高台县| 临泽县| 理塘县| 平江县| 玉树县| 张北县| 毕节市| 揭东县| 房产| 阳新县| 通山县| 项城市| 翁牛特旗|