arm linux 啟動流程之 解壓核心

來源:互聯網
上載者:User

Author-------Dansen-----xzd2734@163.com

從後往前看下編譯產生zImage的過程,我們可以找到程式的入口還是那個很重要
連結檔案,找到它,產生zImage所在的目錄是kernel/arch/arm/boot/compressed/
Make過程為....ld -p -X -T vmlinux.lds head.o misc.o head-s3c2410.o piggy.o
libgcc.o -o vmlinux
然後是用二進位工具objcopy把vmlinux製作成可執行檔二進位映像檔案zImage
這樣在我們就去kernel/arch/arm/boot/compressed/目錄下去找到vmlinux.lds檔案
如果沒有編譯就不會有這個檔案,因為它也是在編譯過程產生的,由同一目錄下的
vmlinux.lds.in產生,開啟這個檔案
ENTRY(_start)
SECTIONS
{
  . = LOAD_ADDR;
  _load_addr = .;

  . = TEXT_START;
  _text = .;

  .text : {
    _start = .;
    *(.start)
    *(.text)
........
入口是_start,而且入口就直接定義在這個檔案中了
入口直接接著.start段,所以程式開始是從.start段開始執行的
如果看看vmlinux.lds的產生過程就應該能找到LOAD_ADDR和TEXT_START的值
實際上這兩個值是由其他兩個變數賦給的 ZRELADDR 和 ZTEXTADDR
在kernel/arch/arm/boot/Makefile中我們可以找到這兩個變數的值
ifeq ($(CONFIG_ARCH_S3C2410),y)
ZTEXTADDR  = 0x30008000
ZRELADDR  = 0x30008000
endif
所以
LOAD_ADDR = 0x30008000
TEXT_START = 0x30008000
看一下vmlinux.lds吧
ENTRY(_start)
SECTIONS
{
  . = 0x30008000;
  _load_addr = .;

  . = 0;
  _text = .;
顯然LOAD_ADDR被賦值了0x30008000
看一下TEXT_START怎麼成0了,我想這應該是一個位移吧,位移是0
所以它還是0x30008000
接著下來就從head.s來開始看代碼吧
  .section ".start", #alloc, #execinstr
/*
 * sort out different calling conventions
 */
  .align
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
這裡一定就是程式的入口了,一般組譯工具的含義就看看英文注釋就是了
有一個要注意的地方,不是一個彙編檔案就是屬於一個段的,不是說先執行完了
head.s再去執行head-s3c2410.s,還是要注意連結的段,顯然head.s
不一會就開始了另一個段.text
  .text
  adr r0, LC0
  ldmia r0, {r1, r2, r3, r4, r5, r6, ip, sp}
  subs r0, r0, r1  @ calculate the delta offset
而我們的head-s3c2410.s呢
 .section ".start", #alloc, #execinstr
__S3C2410_start:
 bic r2, pc, #0x1f
 add r3, r2, #0x4000  @ 16 kb is quite enough...
還是屬於.start段的,所以順序執行下來時先執行head-s3c2410.s,然後再去執行
.text段。head-s3c2410.s主要是cpu的一些初始化工作。接著下來我們會需要把核心
接壓縮,先說說為什麼吧。還是注意到上面產生zImage的檔案中有一個piggy.o,往上
追尋可以看到是piggy.o由那個真正的核心vmlinux產生的,這個vmlinux才是啟動後一直在
啟動並執行核心,原本很大,壓縮以後可以方便地放在flash中,當然其實不壓縮跳到它的
入口也就可以運行了。解壓的核心是準備從LOAD_ADDR = 0x30008000開始的4M空間,會覆蓋
我們的當前啟動並執行代碼,那樣就先把核心解壓到我們這個zImage+分配堆棧0x10000的最後
  cmp r4, r2  //r4 是LOAD_ADDR=0x30008000
  bhs wont_overwrite //r2 是當前代碼的最底部    這裡當然不會跳轉
  add r0, r4, #4096*1024 @ 4MB largest kernel size
  cmp r0, r5  //r5 也是0x30008000 
  bls wont_overwrite //不會跳轉

  mov r5, r2  //r2是(user_stack+4096)在zImage的最後+0x10000
  mov r0, r5  
  mov r3, r7  //machine type
  bl decompress_kernel 
有了r5,r0,r7作為參數,就可以調用misc.c中的decompress_kernel函數進行解壓縮了
這個函數調用的gunzip函數時gcc的庫函數,所以在源碼中找不到的
解壓在r5開始的地方,函數返回的是r0解壓得到的長度。這時候我們需要對代碼經行調整
  add r1, r5, r0  @ end of decompressed kernel
  adr r2, reloc_start
  ldr r3, LC1   //LC1: .word reloc_end - reloc_start
  add r3, r2, r3
1:  ldmia r2!, {r8 - r13}  @ copy relocation code
  stmia r1!, {r8 - r13}
  ldmia r2!, {r8 - r13}
  stmia r1!, {r8 - r13}
  cmp r2, r3  //這裡就把從reloc_start到reloc_end這段我們需要的代碼放到了
  blo 1b  //解壓核心的最後,而在下面我們會將zImage都覆蓋掉
  bl cache_clean_flush
  add pc, r5, r0 //調到調整後的reloc_start,在decompressed kernel後
reloc_start: add r8, r5, r0 //r5解壓核心開始的地方 r0解壓核心的長度
  debug_reloc_start
  mov r1, r4  //r4=0x30008000
1:
  .rept 4
  ldmia r5!, {r0, r2, r3, r9 - r13} @ relocate kernel
  stmia r1!, {r0, r2, r3, r9 - r13}
  .endr

  cmp r5, r8
  blo 1b  //這樣就又把解壓的真正核心移到了0x30008000處
call_kernel: bl cache_clean_flush
  bl cache_off
  mov r0, #0
  mov r1, r7   @ restore architecture number
  mov pc, r4   @ call kernel
上面就是跳到0x30008000這裡去執行真正的核心了吧 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.