Linux內核啟動流程我們分上下兩篇來理解:
上篇是板級引導階段,一般是用匯編實現(xiàn)。
下篇是通用內核啟動階段,一般是C語言實現(xiàn)。
本文先講解上篇,大家看到匯編不用擔心看不懂,在內核啟動階段,沒有特別復雜的流程,都是順序執(zhí)行,只需一句一句閱讀代碼即可。
如何理解板級引導階段?Linux內核支持不同的芯片架構,比如我們熟知的ARM架構、Intel的X86架構、MPIS架構、RISC-V架構等等,可以在Linux內核源碼的arch目錄看到不同的芯片架構源碼放在對應的文件夾內。每種芯片架構的目錄下都包含boot、configs、kernel、lib、Kconfig等文件或目錄。

我們以ARM為例,源碼放在arch/arm目錄下,如下圖所示。

1、文件入口
ARM架構的Linux內核的鏈接腳本文件放在arch/arm/kernel/vmlinux.lds,鏈接腳本定義了整個內核編譯之后的鏈接過程,決定了一個可執(zhí)行程序文件的入口和各個section的存儲位置。Line 21的OUTPUT_ARCH(arm)指示了該鏈接腳本針對的是ARM芯片架構,Line 22的ENTRY(stext)指明了內核入口為stext。因此,我們分析Linux內核啟動流程,就從stext入口分析。

2、函數(shù)入口
ENTRY(stext)是Linux內核的入口函數(shù),該函數(shù)定義在arch/arm/kernel/head.S文件。

根據(jù)代碼注釋,stext是Kernel startup entry point,一般地,它從解壓代碼中獲取,這里解壓代碼是指按照Linux內核壓縮格式提取內核可執(zhí)行文件,它的啟動要求如下:
- 關閉MMU
- 關閉D-cache
- 不關心I-cache
- R0=0
- R1=機器ID
- R2=atags或設備樹文件地址
3、調用safe_svcmode_maskall函數(shù),確保安全進入SVC模式并屏蔽所有中斷

4、獲取處理器ID并找到對應的procinfo
主要實現(xiàn)函數(shù)是__lookup_processor_type。

Linux 內核將每種處理器都抽象為一個struct proc_info_list,因此可以通過process id 來找到對應的 proc_info 結構,__lookup_processor_type 函數(shù)在__lookup_processor_type_data中找到對應處理器的 proc info,將其保存到 R5 寄存器中。



5、調用函數(shù)__vet_atags 驗證 atags 或設備樹(dtb)的合法性

6、調用__create_page_tables創(chuàng)建頁表
7、準備啟動start_kernel

start_kernel函數(shù)是在__mmap_switched函數(shù)內調用的。
上圖的line 146指示將__mmap_switched的地址賦給R13,在line 158的__enable_mmu函數(shù)內的__turn_mmu_on函數(shù)內執(zhí)行R13,成功進入start_kernel.
__INIT
__mmap_switched:
  mov  r7, r1
  mov  r8, r2
  mov  r10, r0
  adr  r4, __mmap_switched_data
  mov  fp, #0
#if defined(CONFIG_XIP_DEFLATED_DATA)
   ARM(  ldr  sp, [r4], #4 )
 THUMB(  ldr  sp, [r4] )
 THUMB(  add  r4, #4 )
  bl  __inflate_kernel_data    @ decompress .data to RAM
  teq  r0, #0
  bne  __error
#elif defined(CONFIG_XIP_KERNEL)
   ARM(  ldmia  r4!, {r0, r1, r2, sp} )
 THUMB(  ldmia  r4!, {r0, r1, r2, r3} )
 THUMB(  mov  sp, r3 )
  sub  r2, r2, r1
  bl  memcpy        @ copy .data to RAM
#endif
   ARM(  ldmia  r4!, {r0, r1, sp} )
 THUMB(  ldmia  r4!, {r0, r1, r3} )
 THUMB(  mov  sp, r3 )
  sub  r2, r1, r0
  mov  r1, #0
  bl  memset        @ clear .bss
  ldmia  r4, {r0, r1, r2, r3}
  str  r9, [r0]      @ Save processor ID
  str  r7, [r1]      @ Save machine type
  str  r8, [r2]      @ Save atags pointer
  cmp  r3, #0
  strne  r10, [r3]      @ Save control register values
  mov  lr, #0
  b  start_kernel
ENDPROC(__mmap_switched)
 電子發(fā)燒友App
                        電子發(fā)燒友App
                     
                 
                 
           
        
