1. 程式人生 > >高通linux系統啟動

高通linux系統啟動

    1. 概述

本平臺採用的是高通apq8009 arm平臺,linux核心版本3.18,採用裝置樹方式。

linux系統啟動過程從軟體方面看可分為:bootloader,linux核心,檔案系統和應用程式。

裝置是以emmc方式啟動的, 燒寫檔案都燒寫到emmc中。上電後讀取emmc,emmc被分了很多區,這裡會有一個分割槽資訊描述,就像x86 windows的mbr, 啟動時候可確定bootloader在emmc中位置,開始啟動bootloader。

bootloader是引導載入程式, uboot是常用的bootloader,它有很多功能,初始化處理器,除錯口,有些還會初始化usb,乙太網,便於資料傳輸;uboot還得支援裝置樹方式;uboot可以通過幫助命令,檢視支援哪些功能,本平臺就可以支援fastboot功能,bootcmd中是對核心影響的引數;

進入linux核心階段,解析裝置樹, 根據裝置樹資訊的的描述,核心匹配了apq8009 arm平臺, 初始化,載入驅動,最後核心會啟動一個init程序。它是Linux系統中的1號程序(Linux系統沒有0號程序)。到此,完成了核心啟動階段的工作,交接給init來管理。

init程序執行一系列的指令碼(startup scripts),可到etc/下檢視,這些指令碼功能可檢測檔案系統,掛載硬碟,設定網路,執行各種應用程式, 等等。

啟動完以後,命令列方式會顯示login 把許可權交給使用者,然後linux系統旅程就開始了。

核心編譯後會產生映像檔案,映像檔案型別分為壓縮和非壓縮方式。這主要是嵌入式系統儲存器容量小,對容量有嚴格要求的,一般採用壓縮式映像檔案,核心啟動用時間換空間。這兩種方式,核心啟動時是不同的,壓縮式啟動的時候,需要解壓映像檔案。

壓縮式映像檔案:uImage和zImage。

非壓縮方式映像檔案:Image, 由elf格式vmlinux轉換而來。

vmlinux屬於未壓縮,帶除錯資訊、符號表

Image是由objcopy工具去除vmlinux除錯資訊、註釋、符號表等內容。

uImage可由工具mkimage 把zImage和64位元組的頭資訊生成uImage。頭資訊描述映像檔案的型別、載入位置、生成時間、大小等資訊。

熟悉了zImage生成過程,才能更容易明白核心是怎麼啟動起來的。linux核心映像檔案生成如下圖:

生成帶裝置樹的核心,命令格式: cat zImage xxx.dtb > zImage-dtb

    1. ARM GCC 內嵌(inline)彙編手冊

可直接看網址:http://www.ethernut.de/en/documents/arm-inline-asm.html

摘錄網址中內容,gcc 中ARM暫存器使用:

Register

Alt. Name

Usage

r0

a1

First function argument Integer function result Scratch register

r1

a2

Second function argument Scratch register

r2

a3

Third function argument Scratch register

r3

a4

Fourth function argument Scratch register

r4

v1

Register variable

r5

v2

Register variable

r6

v3

Register variable

r7

v4

Register variable

r8

v5

Register variable

r9

v6 rfp

Register variable Real frame pointer

r10

sl

Stack limit

r11

fp

Argument pointer

r12

ip

Temporary workspace

r13

sp

Stack pointer

r14

lr

Link register Workspace

r15

pc

Program counter

理解了這些後,看核心中彙編程式碼就容易多了。

該平臺是arm系列處理器,入口程式路徑為arch/arm/;對於非arm平臺, 比如x86, 入口程式路徑為arch/x86/。

用的是壓縮式核心zImage,zImage的入口程式即為 arch/arm/boot/compressed/head.S。

解壓準備階段將執行中斷禁用、分配動態記憶體、初始化BBS區域、初始化頁目錄、開啟快取等任務。

對軟硬體進行初始化完成後,開是執行任務start任務,見下方程式碼:

  1. start:  
  2.         .type   start,#function  
  3.         .rept   7  
  4.         mov r0, r0  
  5.         .endr  
  6.    ARM(     mov r0, r0      )  
  7.    ARM(     b   1f      )  
  8.  THUMB(     adr r12, BSYM(1f)   )  
  9.  THUMB(     bx  r12     )  
  10.         .word   _magic_sig  @ Magic numbers to help the loader  
  11.         .word   _magic_start    @ absolute load/run zImage address  
  12.         .word   _magic_end  @ zImage end address  
  13.         .word   0x04030201  @ endianness flag  
  14.  THUMB(     .thumb          )  
  15. 1:  
  16.  ARM_BE8(   setend  be )            @ go BE8 if compiled for BE8  
  17.         mrs r9, cpsr  
  18. #ifdef CONFIG_ARM_VIRT_EXT  
  19.         bl  __hyp_stub_install  @ get into SVC mode, reversibly  
  20. #endif  
  21.         mov r7, r1          @ save architecture ID  
  22.         mov r8, r2          @ save atags pointer  
  23.         /* 
  24.          * Booting from Angel - need to enter SVC mode and disable 
  25.          * FIQs/IRQs (numeric definitions from angel arm.h source). 
  26.          * We only do this if we were in user mode on entry. 
  27.          */  
  28.         mrs r2, cpsr        @ get current mode  
  29.         tst r2, #3          @ not user?  
  30.         bne not_angel  
  31.         mov r0, #0x17       @ angel_SWIreason_EnterSVC  
  32.  ARM(       swi 0x123456    )   @ angel_SWI_ARM  
  33.  THUMB(     svc 0xab        )   @ angel_SWI_THUMB  
  34. not_angel:  
  35.         safe_svcmode_maskall r0  
  36.         msr spsr_cxsf, r9       @ Save the CPU boot mode in  
  37.                         @ SPSR  
  38.         /* 
  39.          * Note that some cache flushing and other stuff may 
  40.          * be needed here - is there an Angel SWI call for this? 
  41.          */  
  42.         /* 
  43.          * some architecture specific code can be inserted 
  44.          * by the linker here, but it should preserve r7, r8, and r9. 
  45.          */  
  46.         .text  
  47. #ifdef CONFIG_AUTO_ZRELADDR  
  48.         @ determine final kernel image address  
  49.         mov r4, pc  
  50.         and r4, r4, #0xf8000000  
  51.         add r4, r4, #TEXT_OFFSET  
  52. #else  
  53.         ldr r4, =zreladdr  
  54. #endif  
  55.         /* 
  56.          * Set up a page table only if it won't overwrite ourself. 
  57.          * That means r4 < pc && r4 - 16k page directory > &_end. 
  58.          * Given that r4 > &_end is most unfrequent, we add a rough 
  59.          * additional 1MB of room for a possible appended DTB. 
  60.          */  
  61.         mov r0, pc  
  62.         cmp r0, r4  
  63.         ldrcc   r0, LC0+32  
  64.         addcc   r0, r0, pc  
  65.         cmpcc   r4, r0  
  66.         orrcc   r4, r4, #1      @ remember we skipped cache_on  
  67.         blcs    cache_on  

行23是儲存體系結構ID,行24是儲存atags指標。34行開始輸入SVC模式,禁用FIQs/IRQs

行68開始,給DTB留空間,記住跳開cache_on

  1. cache_on:   mov r3, #8          @ cache_on function  
  2.         b   call_cache_fn  
  3. call_cache_fn:  adr r12, proc_types  
  4. #ifdef CONFIG_CPU_CP15  
  5.         mrc p15, 0, r9, c0, c0  @ get processor ID  
  6. #else  
  7.         ldr r9, =CONFIG_PROCESSOR_ID  
  8. #endif  
  9. 1:      ldr r1, [r12, #0]       @ get value  
  10.         ldr r2, [r12, #4]       @ get mask  
  11.         eor r1, r1, r9      @ (real ^ match)  
  12.         tst r1, r2          @       & mask  
  13.  ARM(       addeq   pc, r12, r3     ) @ call cache function  
  14.  THUMB(     addeq   r12, r3         )  
  15.  THUMB(     moveq   pc, r12         ) @ call cache function  
  16.         add r12, r12, #PROC_ENTRY_SIZE  
  17.         b   1b  
  18. /* 
  19.  * Table for cache operations.  This is basically: 
  20.  *   - CPU ID match 
  21.  *   - CPU ID mask 
  22.  *   - 'cache on' method instruction 
  23.  *   - 'cache off' method instruction 
  24.  *   - 'cache flush' method instruction 
  25.  * 
  26.  * We match an entry using: ((real_id ^ match) & mask) == 0 
  27.  * 
  28.  * Writethrough caches generally only need 'on' and 'off' 
  29.  * methods.  Writeback caches _must_ have the flush method 
  30.  * defined. 
  31.  */  
  32.         .align  2  
  33.         .type   proc_types,#object  
  34. proc_types:  
  35.         .word   0x41000000      @ old ARM ID  
  36.         .word   0xff00f000  
  37.         mov pc, lr  
  38.  THUMB(     nop             )  
  39.         mov pc, lr  
  40.  THUMB(     nop             )  
  41.         mov pc, lr  
  42.  THUMB(     nop             )  
  43.         .word   0x41007000      @ ARM7/710  
  44.         .word   0xfff8fe00  
  45.         mov pc, lr  
  46.  THUMB(     nop             )  
  47.         mov pc, lr  
  48.  THUMB(     nop             )  
  49.         mov pc, lr  
  50.  THUMB(     nop             )  
  51.         .word   0x41807200      @ ARM720T (writethrough)  
  52.         .word   0xffffff00  
  53.         W(b)    __armv4_mmu_cache_on  
  54.         W(b)    __armv4_mmu_cache_off  
  55.         mov pc, lr  
  56.  THUMB(     nop             )  
  57.         .word   0x41007400      @ ARM74x  
  58.         .word   0xff00ff00  
  59.         W(b)    __armv3_mpu_cache_on  
  60.         W(b)    __armv3_mpu_cache_off  
  61.         W(b)    __armv3_mpu_cache_flush  
  62.         .word   0x41009400      @ ARM94x  
  63.         .word   0xff00ff00  
  64.         W(b)    __armv4_mpu_cache_on  
  65.         W(b)    __armv4_mpu_cache_off  
  66.         W(b)    __armv4_mpu_cache_flush  
  67.         .word   0x41069260      @ ARM926EJ-S (v5TEJ)  
  68.         .word   0xff0ffff0  
  69.         W(b)    __arm926ejs_mmu_cache_on  
  70.         W(b)    __armv4_mmu_cache_off  
  71.         W(b)    __armv5tej_mmu_cache_flush  
  72.         .word   0x00007000      @ ARM7 IDs  
  73.         .word   0x0000f000  
  74.         mov pc, lr  
  75.  THUMB(     nop             )  
  76.         mov pc, lr  
  77.  THUMB(     nop             )  
  78.         mov pc, lr  
  79.  THUMB(     nop             )  
  80.         @ Everything from here on will be the new ID system.  
  81.         .word   0x4401a100      @ sa110 / sa1100  
  82.         .word   0xffffffe0  
  83.         W(b)    __armv4_mmu_cache_on  
  84.         W(b)    __armv4_mmu_cache_off  
  85.         W(b)    __armv4_mmu_cache_flush  
  86.         .word   0x6901b110      @ sa1110  
  87.         .word   0xfffffff0  
  88.         W(b)    __armv4_mmu_cache_on  
  89.         W(b)    __armv4_mmu_cache_off  
  90.         W(b)    __armv4_mmu_cache_flush  
  91.         .word   0x56056900  
  92.         .word   0xffffff00      @ PXA9xx  
  93.         W(b)    __armv4_mmu_cache_on  
  94.         W(b)    __armv4_mmu_cache_off  
  95.         W(b)    __armv4_mmu_cache_flush  
  96.         .word   0x56158000      @ PXA168  
  97.         .word   0xfffff000  
  98.         W(b)    __armv4_mmu_cache_on  
  99.         W(b)    __armv4_mmu_cache_off  
  100.         W(b)    __armv5tej_mmu_cache_flush  
  101.         .word   0x56050000      @ Feroceon  
  102.         .word   0xff0f0000  
  103.         W(b)    __armv4_mmu_cache_on  
  104.         W(b)    __armv4_mmu_cache_off  
  105.         W(b)    __armv5tej_mmu_cache_flush  
  106. #ifdef CONFIG_CPU_FEROCEON_OLD_ID  
  107.         /* this conflicts with the standard ARMv5TE entry */  
  108.         .long   0x41009260      @ Old Feroceon  
  109.         .long   0xff00fff0  
  110.         b   __armv4_mmu_cache_on  
  111.         b   __armv4_mmu_cache_off  
  112.         b   __armv5tej_mmu_cache_flush  
  113. #endif  
  114.         .word   0x66015261      @ FA526  
  115.         .word   0xff01fff1  
  116.         W(b)    __fa526_cache_on  
  117.         W(b)    __armv4_mmu_cache_off  
  118.         W(b)    __fa526_cache_flush  
  119.         @ These match on the architecture ID  
  120.         .word   0x00020000      @ ARMv4T  
  121.         .word   0x000f0000  
  122.         W(b)    __armv4_mmu_cache_on  
  123.         W(b)    __armv4_mmu_cache_off  
  124.         W(b)    __armv4_mmu_cache_flush  
  125.         .word   0x00050000      @ ARMv5TE  
  126.         .word   0x000f0000  
  127.         W(b)    __armv4_mmu_cache_on  
  128.         W(b)    __armv4_mmu_cache_off  
  129.         W(b)    __armv4_mmu_cache_flush  
  130.         .word   0x00060000      @ ARMv5TEJ  
  131.         .word   0x000f0000  
  132.         W(b)    __armv4_mmu_cache_on  
  133.         W(b)    __armv4_mmu_cache_off  
  134.         W(b)    __armv5tej_mmu_cache_flush  
  135.         .word   0x0007b000      @ ARMv6  
  136.         .word   0x000ff000  
  137.         W(b)    __armv6_mmu_cache_on  
  138.         W(b)    __armv4_mmu_cache_off  
  139.         W(b)    __armv6_mmu_cache_flush  
  140.         .word   0x000f0000      @ new CPU Id  
  141.         .word   0x000f0000  
  142.         W(b)    __armv7_mmu_cache_on  
  143.         W(b)    __armv7_mmu_cache_off  
  144.         W(b)    __armv7_mmu_cache_flush  
  145.         .word   0           @ unrecognised type  
  146.         .word   0  
  147.         mov pc, lr  
  148.  THUMB(     nop             )  
  149.         mov pc, lr  
  150.  THUMB(     nop             )  
  151.         mov pc, lr  
  152.  THUMB(     nop             )  
  153.         .size   proc_types, . - proc_types  
  154.         /* 
  155.          * If you get a "non-constant expression in ".if" statement" 
  156.          * error from the assembler on this line, check that you have 
  157.          * not accidentally written a "b" instruction where you should 
  158.          * have written W(b). 
  159.          */  
  160.         .if (. - proc_types) % PROC_ENTRY_SIZE != 0  
  161.         .error "The size of one or more proc_types entries is wrong."  
  162.         .endif  
  163. /* 
  164.  * Turn off the Cache and MMU.  ARMv3 does not support 
  165.  * reading the control register, but ARMv4 does. 
  166.  * 
  167.  * On exit, 
  168.  *  r0, r1, r2, r3, r9, r12 corrupted 
  169.  * This routine must preserve: 
  170.  *  r4, r7, r8 
  171.  */  
  172.         .align  5  

行2,把常數8寫入暫存器r3中並跳轉到call_cache_fn

開啟彙編程式arch/arm/kernel/head.S,head.S依次完成:開啟 MMU 和 cache,呼叫 decompress_kernel()解壓核心,最後通過呼叫 call_kernel()進入非壓縮核心 Image 的啟動。下面將具體分析在此之後 Linux 核心的啟動過程。