linux核心啟動過程——zImage自解壓

來源:互聯網
上載者:User

 

linux核心啟動過程——基於S3C2410(1)zImage自解壓

轉載自:http://blog.csdn.net/y296144646q/article/details/5683004

linux核心啟動過程——基於S3C2410
(1)zImage自解壓

本文以流行的Samsung公司的S3C2410,mini2440平台和linux-2.6.29為例,介紹如何在ZIX嵌入式開發環境下探索linux核心啟動過程。

Linux核心啟動一般由外部的bootloader引導,也可以在核心頭部嵌入一個loader,實際的應用中這兩種方式都會經常遇到。所以要瞭解核心啟動最開始的過程,必須對bootloader如何引導核心有所熟悉。下面我們從u-boot載入linux核心的代碼開始分析(關於u-boot 自身的啟動流程,請參考u-boot
啟動過程 —— 基於S3C2410
)。

1.處理器核心載入代碼

在u-boot的do_bootm_linux函數裡,實現了處理器架構相關的linux核心載入代碼,特別是tags傳遞。

 

該函數中,在(u-boot-1.6)lib_arm/armlinux.c的90行調用了getenv將bootargs環境變數儲存在commandline

    char *commandline = getenv
("bootargs");

然後解析uImage檔案頭,並且按照頭中的定義分解和載入uImage。所以這部分代碼的運行取決於uImage檔案是如何產生的,本文不做過多敘述,可參考另文瞭解u-boot使用。接下來進行tags設定工作,分別調用了

  • setup_start_tag()
  • setup_memory_tag()
  • setup_commandline_tag()
  • setup_initrd_tag()
  • setup_end_tag()

然後對TLB、cache等進行invalid操作,這是通過在lib_arm/armlinux.c的268行調用cleanup_before_linux()(cpu/arm920t/108)實現,然後即可跳入從uImage中分解出來的核心Image或zImage入口

    cleanup_before_linux ();

    theKernel (0, machid, bd->bi_boot_params);

    /* does not return */

    return;

在s3c2410平台上,該入口theKernel一般是物理地址0x30008000。如果我們使用zImage自解壓核心映像,對應的代碼正是自解壓頭,位置在核心源碼linux-2.6.29的arch/arm/boot/compressed/head.S第 114行的start符號

     start:

                .type   start,#function

                .rept   8

                mov     r0, r0

                .endr

 

                b       1f

                .word   0x016f2818   @ Magic numbers to help the loader

                .word   start        @ absolute load/run zImage address

                .word   _edata       @ zImage end address

1:              mov     r7, r1       @ save architecture ID

                mov     r8, r2       @ save atags pointer

這也標誌著u-boot將系統完全的交給了OS,bootloader生命終止。之後代碼在133行會讀取cpsr並判斷是否處理器處於supervisor模式——從u-boot進入kernel,系統已經處於SVC32模式;而利用angel進入則處於user模式,還需要額外兩條指令。之後是再次確認中斷關閉,並完成cpsr寫入

                mrs     r2, cpsr                @ get current mode

                tst     r2, #3                  @ not user?

                bne     not_angel

                mov     r0, #0x17               @ angel_SWIreason_EnterSVC

                swi     0x123456                @ angel_SWI_ARM

not_angel:

                mrs     r2, cpsr                @ turn off interrupts to

                orr     r2, r2, #0xc0           @ prevent angel from running

                msr     cpsr_c, r2

然後在LC0地址(157行)處將分段資訊匯入r0-r6、ip、sp等寄存器,並檢查代碼是否運行在與連結時相同的目標地址(162行),以決定是否進行處理。由於現在很少有人不使用loader和tags,將zImage燒寫到rom直接從0x0位置執行,所以這個處理是必須的(但是zImage的頭現在也保留了不用loader也可開機能力)。arm架構下自解壓頭一般是連結在0x0地址而被載入到0x30008000運行,所以要修正這個變化。涉及到

  • r5寄存器存放的zImage基地址
  • r6和r12(即ip寄存器)存放的got(global offset table)
  • r2和r3存放的bss段起止地址
  • sp棧指標地址

很簡單,這些寄存器統統被加上一個你也能猜到的位移地址 0x30008000。該地址是s3c2410相關的,其他的ARM處理器可以參考下表

  • PXA2xx是0xa0008000
  • IXP2x00和IXP4xx是0x00008000
  • Freescale i.MX31/37是0x80008000
  • TI davinci DM64xx是0x80008000
  • TI omap系列是0x80008000
  • AT91RM/SAM92xx系列是0x20008000
  • Cirrus EP93xx是0x00008000

這些操作發生在代碼172行開始的地方,下面只粘貼一部分

                add     r5, r5, r0

                add     r6, r6, r0

                add     ip, ip, r0

後面在211行進行bss段的清零工作

not_relocated:  mov     r0, #0

1:              str     r0, [r2], #4            @ clear bss

                str     r0, [r2], #4

                str     r0, [r2], #4

                str     r0, [r2], #4

                cmp     r2, r3

                blo     1b

 然後224行,開啟cache,並為後面解壓縮設定64KB的臨時malloc空間

                bl      cache_on

 

                mov     r1, sp              @ malloc space above stack

                add     r2, sp, #0x10000    @ 64k max 

接下來238行進行檢查,確定核心解壓縮後的Image目標地址是否會覆蓋到zImage頭,如果是則準備將zImage頭轉移到解壓出來的核心後面

                cmp     r4, r2

                bhs     wont_overwrite

                sub     r3, sp, r5              @ > compressed kernel size

                add     r0, r4, r3, lsl #2      @ allow for 4x expansion

                cmp     r0, r5

                bls     wont_overwrite

 

                mov     r5, r2                  @ decompress after malloc space

                mov     r0, r5

                mov     r3, r7

                bl      decompress_kernel

真實情況——在大多數的應用中,核心編譯都會把壓縮的zImage和非壓縮的Image連結到同樣的地址,s3c2410平台下即是0x30008000。這樣做的好處是,人們不用關心核心是Image還是zImage,放到這個位置執行就OK,所以在解壓縮後zImage頭必須為真正的核心讓路。

在250行解壓完畢,核心長度傳回值存放在r0寄存器裡。在核心末尾空出128位元組的棧空間用,並且使其長度128位元組對齊。

                add     r0, r0, #127 + 128      @ alignment + stack

                bic     r0, r0, #127            @ align the kernel length

算出搬移代碼的參數:計算核心末尾地址並存放於r1寄存器,需要搬移代碼原來地址放在r2,需要搬移的長度放在r3。然後執行搬移,並設定好sp指標指向新的棧(原來的棧也會被核心覆蓋掉)

                add     r1, r5, r0              @ end of decompressed kernel

                adr     r2, reloc_start

                ldr     r3, LC1

                add     r3, r2, r3

1:              ldmia   r2!, {r9 - r14}         @ copy relocation code

                stmia   r1!, {r9 - r14}

                ldmia   r2!, {r9 - r14}

                stmia   r1!, {r9 - r14}

 

注意:對於uncompressed kernel是以arch/arm/boot/head.S開始的.對於核心解壓縮部分的code,在 arch/arm/boot/compressed/head.S中經過上面的zImage自解壓然後核心再從arch/arm/boot/head.S中啟動,本文不做討論.

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.