首頁 > 軟體

ARM 平台上的Linux系統啟動流程

2020-06-16 18:01:45

  開始學習嵌入式開發就一直在使用Linux系統作為學習的平台,到現在無論是PC機還是ARM開發板都已經能順利地跑起了Linux系統,但是對Linux 的啟動流程還是不甚了解。於是開始各種百度谷歌,當然看到了各路大神寫的介紹。總的來說就是:bootloader ---->kernel---->root filesystem,當然還介紹了哪個階段完成了哪些工作。比如bootloader 是一上電就拿到cpu 的控制權的,而bootloader實現了硬體的初始化。bootloader儼然就成了power on 之後”第一個吃螃蟹”的程式碼。

  談到這就得想到硬體機制是如何滿足這個功能的了。就拿S3C2440 這個晶片來說(我的硬體平台就是拿這個晶片作為主晶片),CPU內部整合了一塊容量為4KB 的 sram (又叫stapping stone 墊腳石),當系統一上電,NAND controler 就自動地將nand flash 裡的前4K內容複製到墊腳石裡,而PC 指標一上電就指向墊腳石的起始地址0x00000000。這樣這一部分的程式碼就可以得到執行。可以想象,如果這一部分的程式碼就是bootloader 的一部分,那一上電bootloader 不就可以得到執行了麼?事實確實如此,在嵌入式Linux的軟體系統中,nandflash前面一部分程式碼往往就是bootloader ,然後就是kernel, 再接著就是根檔案系統。

  說了這麼多,好像都沒說到啟動流程啊,別著急,咱慢慢談,所謂磨刀不誤砍柴工嘛。

  要說啟動流程,如果只是簡單的介紹從哪到哪,誰幹了啥啥,得到的結果可能只是只知其然不知其所以然。個人覺得隨著CPU的PC指標走,循著程式碼的足跡才能把整個流程理清楚,當找到了程式碼的執行過程,再分析一下程式碼,自然知道了哪個部分完成了哪些事,更重要的是為程式碼的移植打下了堅實的基礎。自然這個過程是痛苦和枯燥的,甚至是看程式碼看了幾天也沒弄明白,不過這也是一種鍛鍊。好了不扯了,馬上進入主題。

bootloder :

  前面說了,bootloader一上電就拿到了cpu 的使用權,它當然得乾一些初始化的工作啊,比如關閉看門狗、設定cpu 的執行模式、設定堆疊等等比較急迫的事情。當然還要對主機板的一些其他硬體進行簡單的初始化 比如網絡卡,顯示屏,nand flash 等等的初始化工作,最後還要負責把Linux核心載入到記憶體中。正所謂責任和權力是並存的嘛,你得到了權益,當然就得付出。當bootloader 完成它的使命之後就會把cpu 的使用權交給下一部分程式碼:kernel 。

kernel:

  在討論kernel 是如何啟動之前,先了解kernel 的組成結構以及是如何得來的。

  下面這張圖是核心編譯即將結束時顯示的資訊:

下面的這張圖說明了上面的編譯過程,

 

  可以看到,當核心原始檔編譯連結成 vmlinux 檔案以後還進行了幾個模組的編譯和連結。其中vmlinux 是ELF格式的object檔案,這種檔案只是各個原始碼經過連線以後的得到的檔案,並不能在arm平台上執行。經過objcopy這個工具轉換以後,得到了二進位制格式檔案Image,Image檔案相比於vmlinux 檔案,除了格式不同以外,還被去除了許多注釋和偵錯的資訊。Image檔案經過壓縮以後得到了piggy.gz ,這個檔案僅僅是Image的壓縮版,並無其他不同。接著編譯生成另外幾個模組檔案misc.o big_endian.o head.o head-xscale.o,這幾個檔案組成一個叫bootstrap loader 的元件,又叫載入程式。編譯生成 piggy.o 檔案。最後piggy.o檔案和bootstrap loader 組成一個bootable kernel Image 檔案(可啟動檔案)。

  可以看到最後得到的可執行檔案就是上圖最右邊那個,這也是我們最後燒寫到開發板的映象。其中piggy.o 就是核心映象,而剩下的幾個檔案就組成了載入程式。  

  下面開始討論CPU的流轉過程:

  還是用一個圖來展示:

  從上圖可以看出,系統一上電就開始執行bootloader 當bootloader 執行完以後,把控制權交給了載入程式的head.o 檔案裡的start 標號處,當載入程式完成引導工作以後就將控制權轉給真正的核心的head.o 檔案裡的start 標號處。這裡就是核心的入口點,最後核心的head.o將控制交給main.o 的start_kernel 函數。這樣,通過檢視相應的程式碼就可以知道這些程式碼到底完成了哪些工作。在這裡我們可以找到相應的程式碼,分析一下,看它們到底完成哪些事。下面是我的分析結果:

載入程式: head.o從bootloader接過控制權,並完成如下任務:

    1. 使能 I/D caches ,關閉中斷 , 建立C執行環境(即設定堆疊)由 head.o 和head-xscal.o 完成   

    2. 解壓縮並重定位程式碼 ,由misc.o 完成

    3. 其他硬體相關的設定,如big.endian.o 為cpu設定大端模式

核心入口點:從載入程式接過控制權,完成如下任務

    1. 檢查有效的cpu 和cpu的資訊

    2. 建立初始化頁表入口

    3. 使能MMU

    4. 檢測錯誤並報告

    5. 跳轉到核心本身 main.c 檔案裡的 start_kernel()函數

 

 核心啟動:從kernel 的head.o接過控制權,開始核心的啟動,在這裡完成核心的初始化,如核心各個子系統的初始化。

本文永久更新連結地址http://www.linuxidc.com/Linux/2015-04/116545.htm


IT145.com E-mail:sddin#qq.com