Linux內(nèi)核自解壓過(guò)程
uboot完成系統(tǒng)引導(dǎo)以后,執(zhí)行環(huán)境變量bootm中的命令;即,將Linux內(nèi)核調(diào)入內(nèi)存中并調(diào)用do_bootm函數(shù)啟動(dòng)內(nèi)核,跳轉(zhuǎn)至kernel的起始位置。如果內(nèi)核沒(méi)有被壓縮,則直接啟動(dòng);如果內(nèi)核被壓縮過(guò),則需要進(jìn)行解壓,被壓縮過(guò)的kernel頭部有解壓程序。
壓縮過(guò)的kernel入口第一個(gè)文件源碼位置在/kernel/arch/arm/boot/compressed/head.S。它將調(diào)用decompress_kernel()函數(shù)進(jìn)行解壓,解壓完成后,打印出信息“Uncompressing Linux...done,booting the kernel”。解壓縮完成后,調(diào)用gunzip()函數(shù)(或unlz4()、或bunzip2()、或unlz())將內(nèi)核放于指定位置,開始啟動(dòng)內(nèi)核。
2. Linux內(nèi)核啟動(dòng)準(zhǔn)備階段
由內(nèi)核鏈接腳本/kernel/arch/arm/kernel/vmlinux.lds可知,內(nèi)核入口函數(shù)為stext(/kernel/arch/arm/kernel/head.S)。內(nèi)核解壓完成后,解壓縮代碼調(diào)用stext函數(shù)啟動(dòng)內(nèi)核。
ENTRY(stext) setmodePSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode@ and irqs disabled mrcp15, 0, r9, c0, c0 @ 獲得處理器ID,并存儲(chǔ)在r9寄存器中 bl__lookup_processor_type @ 結(jié)果返回:描述處理器結(jié)構(gòu)體的地址 r5=procinfo ,處理器ID號(hào) r9=cpuid movsr10, r5 @ invalid processor (r5=0)?判斷內(nèi)核是否支持該處理器 beq__error_p @ yes, error 'p' bl__lookup_machine_type @結(jié)果返回:描述機(jī)器(開發(fā)板)的結(jié)構(gòu)體地址 r5=machinfo movsr8, r5 @ invalid machine (r5=0)?判斷內(nèi)核是否支持該機(jī)器(開發(fā)板) beq__error_a @ yes, error 'a' bl__vet_atags @檢查uboot給內(nèi)核的傳參ATAGS格式是否正確 bl__create_page_tables @建立虛擬地址映射頁(yè)表 ldrr13, __switch_data @ address to jump to after
(1)關(guān)閉IRQ、FIQ中斷,進(jìn)入SVC模式。調(diào)用setmode宏實(shí)現(xiàn);
(2)校驗(yàn)處理器ID,檢驗(yàn)內(nèi)核是否支持該處理器;若不支持,則停止啟動(dòng)內(nèi)核。調(diào)用__lookup_processor_type函數(shù)實(shí)現(xiàn);
(3)校驗(yàn)機(jī)器碼,檢驗(yàn)內(nèi)核是否支持該機(jī)器;若不支持,則停止啟動(dòng)內(nèi)核。調(diào)用__lookup_machine_type函數(shù)實(shí)現(xiàn);
(4)檢查uboot向內(nèi)核傳參ATAGS格式是否正確,調(diào)用__vet_atars函數(shù)實(shí)現(xiàn);
(5)建立虛擬地址映射頁(yè)表。此處建立的頁(yè)表為粗頁(yè)表,在內(nèi)核啟動(dòng)前期使用。Linux對(duì)內(nèi)存管理有更精細(xì)的要求,隨后會(huì)重新建立更精細(xì)的頁(yè)表。調(diào)用__create_page_tables函數(shù)實(shí)現(xiàn)。
(6)跳轉(zhuǎn)執(zhí)行__switch_data函數(shù),其中調(diào)用__mmap_switched完成最后的準(zhǔn)備工作。
1)復(fù)制數(shù)據(jù)段、清除bss段,目的是構(gòu)建C語(yǔ)言運(yùn)行環(huán)境; 2)保存處理器ID號(hào)、機(jī)器碼、uboot向內(nèi)核傳參地址; 3)b start_kernel跳轉(zhuǎn)至內(nèi)核初始化階段。
__switch_data: .long__mmap_switched .......................................................... __mmap_switched: adrr3, __switch_data + 4 ldmiar3!, {r4, r5, r6, r7} cmpr4, r5@ Copy data segment if needed 1:cmpner5, r6 ldrnefp, [r4], #4 strnefp, [r5], #4 bne1b movfp, #0@ Clear BSS (and zero fp) 1:cmpr6, r7 strccfp, [r6],#4 bcc1b ARM(ldmiar3, {r4, r5, r6, r7, sp}) THUMB(ldmiar3, {r4, r5, r6, r7}) THUMB(ldrsp, [r3, #16]) strr9, [r4]@ Save processor ID strr1, [r5]@ Save machine type strr2, [r6]@ Save atags pointer bicr4, r0, #CR_A@ Clear 'A' bit stmiar7, {r0, r4}@ Save control register values bstart_kernel ENDPROC(__mmap_switched)
3. Linux內(nèi)核初始化階段
此階段從start_kernel函數(shù)開始。start_kernel函數(shù)是所有Linux平臺(tái)進(jìn)入系統(tǒng)內(nèi)核初始化的入口函數(shù)。它的主要工作是完成剩余與硬件平臺(tái)相關(guān)的初始化工作,在進(jìn)行一系列與內(nèi)核相關(guān)的初始化之后,調(diào)用第一個(gè)用戶進(jìn)程init并等待其執(zhí)行。至此,整個(gè)內(nèi)核啟動(dòng)完成。
3.1 start_kernel函數(shù)的主要工作
start_kernel函數(shù)主要完成內(nèi)核相關(guān)的初始化工作。具體包括以下部分:
(1)內(nèi)核架構(gòu) 、通用配置相關(guān)初始化
(2) 內(nèi)存管理相關(guān)初始化
(3)進(jìn)程管理相關(guān)初始化
(4)進(jìn)程調(diào)度相關(guān)初始化
(5)網(wǎng)絡(luò)子系統(tǒng)管理
(6)虛擬文件系統(tǒng)
(7)文件系統(tǒng)
3.2 start_kernel函數(shù)流中的關(guān)鍵函數(shù)
(1)setup_arch(&command_line)函數(shù)
內(nèi)核架構(gòu)相關(guān)的初始化函數(shù),是非常重要的一個(gè)初始化步驟。其中,包含了處理器相關(guān)參數(shù)的初始化、內(nèi)核啟動(dòng)參數(shù)(tagged list)的獲取和前期處理、內(nèi)存子系統(tǒng)的早期初始化。
command_line實(shí)質(zhì)是uboot向內(nèi)核傳遞的命令行啟動(dòng)參數(shù),即uboot中環(huán)境變量bootargs的值。若uboot中bootargs的值為空,command_line = default_command_line,即為內(nèi)核中的默認(rèn)命令行參數(shù),其值在.config文件中配置,對(duì)應(yīng)CONFIG_CMDLINE配置項(xiàng)。
(2)setup_command_line、parse_early_param以及parse_args函數(shù)
這些函數(shù)都是在完成命令行參數(shù)的解析、保存。譬如,cmdline = console=ttySAC2,115200 root=/dev/mmcblk0p2 rw init=/linuxrc rootfstype=ext3;解析為一下四個(gè)參數(shù):
console=ttySAC2,115200 //指定控制臺(tái)的串口設(shè)備號(hào),及其波特率
root=/dev/mmcblk0p2 rw //指定根文件系統(tǒng)rootfs的路徑
init=/linuxrc //指定第一個(gè)用戶進(jìn)程init的路徑
rootfstype=ext3 //指定根文件系統(tǒng)rootfs的類型
(3)sched_init函數(shù)
初始化進(jìn)程調(diào)度器,創(chuàng)建運(yùn)行隊(duì)列,設(shè)置當(dāng)前任務(wù)的空線程。
(4)rest_init函數(shù)
rest_init函數(shù)的主要工作如下:
1)調(diào)用kernel_thread函數(shù)啟動(dòng)了2個(gè)內(nèi)核線程,分別是:kernel_init和kthreadd。kernel_init線程中調(diào)用prepare_namespace函數(shù)掛載根文件系統(tǒng)rootfs;然后調(diào)用init_post函數(shù),執(zhí)行根文件系統(tǒng)rootfs下的第一個(gè)用戶進(jìn)程init。用戶進(jìn)程有4個(gè)備選方案,若command_line中init的路徑錯(cuò)誤,則會(huì)執(zhí)行備用方案。第一備用:/sbin/init,第二備用:/etc/init,第三備用:/bin/init,第四備用:/bin/sh。 2)調(diào)用schedule函數(shù)開啟內(nèi)核調(diào)度系統(tǒng); 3)調(diào)用cpu_idle函數(shù),啟動(dòng)空閑進(jìn)程idle,完成內(nèi)核啟動(dòng)。
審核編輯:劉清
-
處理器
+關(guān)注
關(guān)注
68文章
19884瀏覽量
235029 -
SVC
+關(guān)注
關(guān)注
0文章
33瀏覽量
12444 -
LINUX內(nèi)核
+關(guān)注
關(guān)注
1文章
317瀏覽量
22387 -
FIQ
+關(guān)注
關(guān)注
0文章
9瀏覽量
2411
原文標(biāo)題:linux 內(nèi)核啟動(dòng)流程分析
文章出處:【微信號(hào):LinuxHub,微信公眾號(hào):Linux愛(ài)好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
Linux內(nèi)核自解壓過(guò)程
嵌入式Linux主要有哪幾部分呢
嵌入式linux內(nèi)核啟動(dòng)流程是怎樣的
Linux內(nèi)核啟動(dòng)全過(guò)程解析
linux內(nèi)核啟動(dòng)內(nèi)核解壓過(guò)程分析
基于Linux 2.6內(nèi)核Makefile分析

關(guān)于Linux 2.6內(nèi)核Makefile的分析
Linux內(nèi)核移植相關(guān)代碼解析
ARM處理器上的linux內(nèi)核啟動(dòng)的過(guò)程詳細(xì)資料概述

嵌入式Linux內(nèi)核移植相關(guān)代碼分析
Linux內(nèi)核GPIO操作函數(shù)的詳解分析
STM32MP157 Linux系統(tǒng)移植開發(fā)篇8:Linux內(nèi)核配置方法及編譯

評(píng)論