1000部丰满熟女富婆视频,托着奶头喂男人吃奶,厨房挺进朋友人妻,成 人 免费 黄 色 网站无毒下载

首頁 > 文章中心 > 正文

ARM Linu啟動過程

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

摘要:嵌入式Linux的可移植性使得我們可以在各種電子產品上看到它的身影。對于不同體系結構的處理器來說Linux的啟動過程也有所不同。本文以S3C2410ARM處理器為例,詳細分析了系統上電后bootloader的執行流程及ARMLinux的啟動過程。

關鍵詞:ARMLinuxbootloader啟動過程

Abstract:

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

Keywords:ARMLinuxbootloaderstart-upprocedure

1.引言

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

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

Linux內核,文件系統,應用程序。

其中bootloader是系統啟動或復位以后執行的第一段代碼,它主要用來初始化處理器及外設,然后調用Linux內核。Linux內核在完成系統的初始化之后需要掛載某個文件系統做為根文件系統(RootFilesystem)。根文件系統是Linux系統的核心組成部分,它可以做為Linux系統中文件和數據的存儲區域,通常它還包括系統配置文件和運行應用軟件所需要的庫。應用程序可以說是嵌入式系統的“靈魂”,它所實現的功能通常就是設計該嵌入式系統所要達到的目標。如果沒有應用程序的支持,任何硬件上設計精良的嵌入式系統都沒有實用意義。

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

2.Bootloader

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

2.2Bootloader的執行過程不同的處理器上電或復位后執行的第一條指令地址并不相同,對于ARM處理器來說,該地址為0x00000000。對于一般的嵌入式系統,通常把Flash等非易失性存儲器映射到這個地址處,而bootloader就位于該存儲器的最前端,所以系統上電或復位后執行的第一段程序便是bootloader。而因為存儲bootloader的存儲器不同,bootloader的執行過程也并不相同,下面將具體分析。

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

1)初始化RAM

因為Linux內核一般都會在RAM中運行,所以在調用Linux內核之前bootloader必須設置和初始化RAM,為調用Linux內核做好準備。初始化RAM的任務包括設置CPU的控制寄存器參數,以便能正常使用RAM以及檢測RAM大小等。

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

3)檢測處理器類型

Bootloader在調用Linux內核前必須檢測系統的處理器類型,并將其保存到某個常量中提供給Linux內核。Linux內核在啟動過程中會根據該處理器類型調用相應的初始化程序。

4)設置Linux啟動參數

Bootloader在執行過程中必須設置和初始化Linux的內核啟動參數。目前傳遞啟動參數主要采用兩種方式:即通過structparam_struct和structtag(標記列表,taggedlist)兩種結構傳遞。structparam_struct是一種比較老的參數傳遞方式,在2.4版本以前的內核中使用較

多。從2.4版本以后Linux內核基本上采用標記列表的方式。但為了保持和以前版本的兼容性,它仍支持structparam_struct參數傳遞方式,只不過在內核啟動過程中它將被轉換成標記列表方式。

標記列表方式是種比較新的參數傳遞方式,它必須以ATAG_CORE開始,并以ATAG_NONE結尾。中間可以根據需要加入其他列表。Linux內核在啟動過程中會根據該啟動參數進行相應的初始化工作。

5)調用Linux內核映像

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

.Linux內核的啟動過程

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

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

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

3.1Linux內核入口

Linux非壓縮內核的入口位于文件/arch/arm/kernel/head-armv.S中的stext段。該段的基地址就是壓縮內核解壓后的跳轉地址。如果系統中加載的內核是非壓縮的Image,那么bootloader將內核從Flash中拷貝到RAM后將直接跳到該地址處,從而啟動Linux內核。不同體系結構的Linux系統的入口文件是不同的,而且因為該文件與具體體系結構有關,所以一般均用匯編語言編寫[3]。對基于ARM處理的Linux系統來說,該文件就是head-armv.S。該程序通過查找處理器內核類型和處理器類型調用相應的初始化函數,再建立頁表,最后跳轉到start_kernel()函數開始內核的初始化工作。

檢測處理器內核類型是在匯編子函數__lookup_processor_type中完成的。通過以下代碼可實現對它的調用:bl__lookup_processor_type。__lookup_processor_type調用結束返回原程序時,會將返回結果保存到寄存器中。其中r8保存了頁表的標志位,r9保存了處理器的ID號,r10保存了與處理器相關的struproc_info_list結構地址。

檢測處理器類型是在匯編子函數__lookup_architecture_type中完成的。與__lookup_processor_type類似,它通過代碼:“bl__lookup_processor_type”來實現對它的調用。該函數返回時,會將返回結構保存在r5、r6和r7三個寄存器中。其中r5保存了RAM的起始基地址,r6保存了I/O基地址,r7保存了I/O的頁表偏移地址。當檢測處理器內核和處理器類型結束后,將調用__create_page_tables子函數來建立頁表,它所要做的工作就是將RAM基地址開始的4M空間的物理地址映射到0xC0000000開始的虛擬地址處。對筆者的S3C2410開發板而言,RAM連接到物理地址0x30000000處,當調用__create_page_tables結束后0x30000000~0x30400000物理地址將映射到0xC0000000~0xC0400000虛擬地址處。

當所有的初始化結束之后,使用如下代碼來跳到C程序的入口函數start_kernel()處,開始之后的內核初始化工作:

bSYMBOL_NAME(start_kernel)

3.2start_kernel函數

start_kernel是所有Linux平臺進入系統內核初始化后的入口函數,它主要完成剩余的與硬件平臺相關的初始化工作,在進行一系列與內核相關的初始化后,調用第一個用戶進程-init進程并等待用戶進程的執行,這樣整個Linux內核便啟動完畢。該函數所做的具體工作有[4][5]

1)調用setup_arch()函數進行與體系結構相關的第一個初始化工作;

對不同的體系結構來說該函數有不同的定義。對于ARM平臺而言,該函數定義在arch/arm/kernel/Setup.c。它首先通過檢測出來的處理器類型進行處理器內核的初始化,然后通過bootmem_init()函數根據系統定義的meminfo結構進行內存結構的初始化,最后調用paging_init()開啟MMU,創建內核頁表,映射所有的物理內存和IO空間。

2)創建異常向量表和初始化中斷處理函數;

3)初始化系統核心進程調度器和時鐘中斷處理機制;

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

ARM-Linux在初始化過程中一般都會初始化一個串口做為內核的控制臺,這樣內核在啟動過程中就可以通過串口輸出信息以便開發者或用戶了解系統的啟動進程。

5)創建和初始化系統cache,為各種內存調用機制提供緩存,包括;動態內存分配,虛擬文件系統(VirtualFileSystem)及頁緩存。

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

7)初始化系統的進程間通信機制(IPC);

當以上所有的初始化工作結束后,start_kernel()函數會調用rest_init()函數來進行最后的初始化,包括創建系統的第一個進程-init進程來結束內核的啟動。Init進程首先進行一系列的硬件初始化,然后通過命令行傳遞過來的參數掛載根文件系統。最后init進程會執行用戶傳遞過來的“init=”啟動參數執行用戶指定的命令,或者執行以下幾個進程之一:

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

當所有的初始化工作結束后,cpu_idle()函數會被調用來使系統處于閑置(idle)狀態并等待用戶程序的執行。至此,整個Linux內核啟動完畢。

4.結論

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

參考文獻

[1]詹榮開.嵌入式系統bootloader技術內幕[EB/OL]./developerworks/cn/linux/l-btloader/index.html,2003.12.

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

[3]劉淼.嵌入式系統接口設計與Linux驅動程序開發[M].北京航空航天大學出版社.2006.6

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

[5]ClaudiaSalzbergRodriguez,GordonFischer,StevenSmolski.Linux內核編程[M].陳莉君,賀炎,劉霞林.機械工業出版社.2006.7

主站蜘蛛池模板: 固始县| 中卫市| 阿巴嘎旗| 苏尼特右旗| 青州市| 中方县| 广宁县| 东安县| 盐边县| 察哈| 潜江市| 蒙自县| 海城市| 博乐市| 九龙坡区| 时尚| 宁河县| 彭水| 贵港市| 保靖县| 盖州市| 赫章县| 芦溪县| 许昌县| 奉节县| 阿拉善盟| 闻喜县| 邯郸县| 清原| 册亨县| 肥城市| 南昌县| 泰来县| 农安县| 辛集市| 兴山县| 额济纳旗| 措勤县| 边坝县| 通榆县| 焦作市|