linux啟動流程分析-核心解壓縮過程
核心壓縮和解壓縮**都在目錄kernel/arch/arm/boot/compressed,
編譯完成後將產生vmlinux、head.o、misc.o、head-xscale.o、piggy.o這幾個檔案,
head.o是核心的頭部檔案,負責初始設定;
misc.o將主要負責核心的解壓工作,它在head.o之後;
head-xscale.o檔案主要針對xscale的初始化,將在鏈結時與head.o合併;
piggy.o是乙個中間檔案,其實是乙個壓縮的核心(kernel/vmlinux),只不過沒有和初始化檔案及解壓檔案鏈結而已;
vmlinux是(沒有--lw:zimage是壓縮過的核心)壓縮過的核心,就是由piggy.o、head.o、misc.o、head-xscale.o組成的。
在bootloader完成系統的引導以後並將linux核心調入記憶體之後,呼叫bootlinux(),
這個函式將跳轉到kernel的起始位置。如果kernel沒有壓縮,就可以啟動了。
如果kernel壓縮過,則要進行解壓,在壓縮過的kernel頭部有解壓程式。
壓縮過得kernel入口第乙個檔案原始碼位置在arch/arm/boot/compressed/head.s。
它將呼叫函式decompress_kernel(),這個函式在檔案arch/arm/boot/compressed/misc.c中,
decompress_kernel()又呼叫proc_decomp_setup(),arch_decomp_setup()進行設定,
然後使用在列印出資訊「uncompressing linux...」後,呼叫gunzip()。將核心放於指定的位置。
以下分析head.s檔案:
(1)對於各種armcpu的debug輸出設定,通過定義巨集來統一操作。
(2)設定kernel開始和結束位址,儲存architecture id。
(3)如果在arm2以上的cpu中,用的是普通使用者模式,則公升到超級使用者模式,然後關中斷。
(4)分析lc0結構delta offset,判斷是否需要過載核心位址(r0存入偏移量,判斷r0是否為零)。
這裡是否需要過載核心位址,我以為主要分析arch/arm/boot/makefile、arch/arm/boot/compressed/makefile
和arch/arm/boot/compressed/vmlinux.lds.in三個檔案,主要看vmlinux.lds.in鏈結檔案的主要段的位置,
load_addr(_load_addr)=0xa0008000,而對於text_start(_text、_start)的位置只設為0,bss_start(__bss_start)=align(4)。
對於這樣的結果依賴於,對核心解壓的執行方式,也就是說,核心解壓前是在記憶體(ram)中還是在flash上,
因為這裡,我們的bootloader將壓縮核心(zimage)移到了ram的0xa0008000位置,我們的壓縮核心是在記憶體(ram)從0xa0008000位址開始順序排列,
因此我們的r0獲得的偏移量是載入位址(0xa0008000)。接下來的工作是要把核心映象的相對位址轉化為記憶體的實體地址,即過載核心位址。
(5)需要過載核心位址,將r0的偏移量加到bss region和got table中。
(6)清空bss堆疊空間r2-r3。
(7)建立c程式執行需要的快取,並賦於64k的棧空間。
(8)這時r2是快取的結束位址,r4是kernel的最後執行位址,r5是kernel境象檔案的開始位址。檢查是否位址有衝突。
將r5等於r2,使decompress後的kernel位址就在64k的棧之後。
(9)呼叫檔案misc.c的函式decompress_kernel(),解壓核心於快取結束的地方(r2位址之後)。此時各暫存器值有如下變化:
r0為解壓後kernel的大小
r4為kernel執行時的位址
r5為解壓後kernel的起始位址
r6為cpu型別值(processor id)
r7為系統型別值(architecture id)
(10)將reloc_start**拷貝之kernel之後(r5+r0之後),首先清除快取,而後執行reloc_start。
(11)reloc_start將r5開始的kernel過載於r4位址處。
(12)清除cache內容,關閉cache,將r7中architecture id賦於r1,執行r4開始的kernel**。
下面簡單介紹一下解壓縮過程,也就是函式decompress_kernel實現的功能:
解壓縮**位於kernel/lib/inflate.c,inflate.c是從gzip源程式中分離出來的。包含了一些對全域性資料的直接引用。
在使用時需要直接嵌入到**中。gzip壓縮檔案時總是在前32k位元組的範圍內尋找重複的字串進行編碼,
在解壓時需要乙個至少為32k位元組的解壓緩衝區,它定義為window[wsize]。inflate.c使用get_byte()讀取輸入檔案,
它被定義成巨集來提高效率。輸入緩衝區指標必須定義為inptr,inflate.c中對之有減量操作。inflate.c呼叫flush_window()
來輸出window緩衝區中的解壓出的位元組串,每次輸出長度用outcnt變數表示。在flush_window()中,還必
須對輸出位元組串計算crc並且重新整理crc變數。在呼叫gunzip()開始解壓之前,呼叫makecrc()初始化crc計算表。
最後gunzip()返回0表示解壓成功。
我們在核心啟動的開始都會看到這樣的輸出:
uncompressing linux...done, booting the kernel.
這也是由decompress_kernel函式內部輸出的,它呼叫了puts()輸出字串,
puts是在kernel/include/asm-arm/arch-pxa/uncompress.h中實現的。
執行完解壓過程,再返回到head.s中,啟動核心:
call_kernel: bl cache_clean_flush
bl cache_off
mov r0, #0
mov r1, r7 @ restore architecture number
mov pc, r4 @ call kernel
下面就開始真正的核心了。
linux 核心 核心啟動流程
cs是 段暫存器,ip是指令指標暫存器 相當於偏移位址 儲存的是 指令的位址。cs ip共同作用生成了 位址,具體演算法是cs左移4位 ip即是 位址。例如cs 0xf000,ip 0xfff0,則 位址為0xffff0.global globl 命令 global symbol global 使得...
uboot啟動linux核心流程分析(三)
uboot bootz命令流程圖 uboot啟動linux核心是使用bootz命令,bootz是如何啟動linux核心?uboot的生命週期是怎麼終止的?linux是如何啟動?啟動linux核心的時候都會用到乙個重要的區域性變數 images,images在檔案cmd bootm.c中有定義。ima...
linux核心啟動流程
linux核心啟動流程 計算機在啟動時都是先加電,然後進行硬體檢測並引導作業系統的初始化程式,然後作業系統的初始化程式程負責讀入系統核心並建產系統的執行環境.一這過程相對來說比較復而且與cpu體系結構相關,這裡我們通過linux並以i386的體系結構對這一過程進行較為詳細的說明.1 硬體檢測 當機器...