Kernel启动流程

        我們現在用的kernel是壓縮過的zImage,加上64byte頭部信息,變成了uImage,所以kernel的前面部份是自解壓縮代碼,之後才跳到真正的kernel執行代碼去。所以從uboot跳到的是arch/arm/boot/compressed/head.S中執行,這一段還沒有仔細研究過,不過主要流程是,從arch/arm/boot/compressed/vmlinux.lds可知道第一航執行的代碼是start處:

131行表示連續執行132行8次,136行是linux kernel的魔術數,在uboot檢查kernel時會用到,忘記的可以回到uboot中看一下:

306行跳到arch/arm/boot/compressed/misc.c中執行自解壓函數:

然後307行跳到:

執行572行后就跳到了arch/arm/kernel/head.S中執行真正的kernel代碼。

在arch/arm/kernel/vmlinux.lds中:

可以看到lable 為stext的地方就是kernel的入口,它在arch/arm/kernel/head.S中:

第一句先用協處理器取得processor id,然後調用__lookup_processor_type函數來查找當前內核是否支持這種處理器,在head-common.S中:


簡單說一下,執行完161行后r3中的值為194行中__proc_info_begin的物理地址,執行完162行后,r5= __proc_info_begin
   r6=__proc_info_end,r7=196行代碼的虛擬地址,164行算出虛擬和物理地址的差值,165行后r5= __proc_info_begin的物理地址, 166行后r6=__proc_info_end的物理地址;說到這裡先插說一下地址__proc_info_begin和地址__proc_info_end之間方的的什麽東西。在arch/arm/mm目錄下定義了kernel所支持的arm CPU架構,我們的S5PV210屬於V7架構,看到裏面有:


這裡定義的是一個proc_info_list結構體,該結構體原型在procinfo.h中,從327行可以看到這段代碼編譯時被放在.proc.info.init段,.proc.info.init在連接腳本arch/arm/kernel/vmlinux.lds中定義:

381行就可以看出,地址__proc_info_begin和地址__proc_info_end之間放的就是proc_info_list結構體。

回到head-common.S中,167行對比看是否找到了合適的proc_info_list,我們這裡編譯進來的只有一個proc_info_list,一定可以找到的了,170行比對,找的的話跳到175行返回,如果萬一找不到跳到的話171行跳到下一個proc_info_list,172行檢察如果還有proc_info_list則跳到167行繼續對比,否則執行174行r5標誌為unknown processor,然後返回。

這樣回到arch/arm/kernel/head.S中:80行比對取得的processor ID和讀出來的processor ID是否一致,不是則81行錯誤,CPU掛掉了,是則執行82行,__lookup_machine_type也在arch/arm/kernel/head-common.S中定義:

和前面的__proc_info_begin差不多一樣的了,從地址__arch_info_begin和地址__arch_info_end之間找結構體,

.arch.info.init放的是結構體machine_desc,我們S5PV210的該結構體定義在machine.c中,

MACHINE_START和MACHINE_END是一個宏,看它的宏定義就明白了,在arch.h中:

看這個宏的53行就知道這個結構體編譯鏈接時被放在.arch.info.init段,其他的不想多說,至於這裡 展開后nr=MACH_TYPE_PDC2是如何轉換為機器號5001的,看arch/arm/tools裏面的3個腳本文件,先看Makefile:



它要生成一個include/generated/mach-types.h的頭文件(原來是沒有的),如何生成呢?用AWK命令運行gen-mach-types文件中的腳本,解析mach-types中的文件生成的,感興趣的可以研究AWK這個強大的文本處理工具的語法,這裡我們知道會生成mach-types.h就可以了,所以看看它的內容:

回到arch/arm/kernel/head-common.S中,218行找到並且與r1的相等就返回,r1放的是什麽?就是前面uboot中thekernel函數傳進來的第一個參數,還記得是什麼嗎?就是uboot中定義的machine id,值為5001,不記得的返回去看一下Uboot啟動流程.ppt

看2952行就行了,其他的不多說。
回到arch/arm/kernel/head.S中,接下來是使能mmu等,這是一些瘋狂的代碼,感興趣的可以研究看看,最後會執行到97行:

__switch_data在arch/arm/kernel/head-common.S 中,貼出該函數的後半部份:

最後64行就跳到了c代碼中,它在init/main.c中:


看573行,函數在arch/arm/kernel/setup.c中:

680行,machine_arch_type前面有說過,在include/generated/mach-types.h中,這裡會查找到我們在machine.c中定義的machine_desc結構體,689行,取出boot_params的值,我們這裡就是0x30000100,正好是uboot傳遞過來的參數地址,這就是uboot和kernel的約定了,不明白的回頭看看uboot傳了什麽值過來。

695-698行,爲了兼容舊版本的結構體,我們這裡不執行,701行,meminfo結構體是一個全局變量,以後很多地方會用到這個結構體中的數據。705行把ATAG_MEM的標記去掉,意思就是不需要uboot傳遞過來的memery參數了,因為kernel裏面自己有設置;707行開始解析tag參數,進去分析看看:

636行只要t->hdr.size不為0就繼續解析,我們uboot中tag結束的標記就是賦值tag結構體的hdr.size值為0;637行:

.taglist.init在哪裡?進到arch/arminclude/asm/setup.h中:

只要用宏__tagtable定義的所有tagtable結構體在編譯連接時候都會放到__tagtable_begin開始的地址中,回到setup.c中看看定義了那些tagtable結構體:

有很多,uboot中有的類型這裡都會有,好了,繼續回到剛才622行,這裡哪一個出來分析看看,比如tag==ATAG_CMDLINE,uboot和kernel都有定義,所以622行成立,623行執行parse_tag_cmdline函數:



其餘的自行分析,相信難不倒各位。不過要注意tagtable結構體在arch/arm/init.c中還有定義,比如ramdisk分析就是在該文件中接著往下:

752-754行,賦值并在其他地方執行machine.c中的函數。回到main.c中,一路下來多是一些初始化工作了,一般都不會有問題,也不需要我們更改,到最後掛載ramdisk時候可能會遇到問題,比如掛載不成功。要使用ramdisk,在menuconfig->General setup  ---> 選中[*] Initial RAM filesystem and RAM disk (initramfs/initrd) support ,ramdisk解壓掛載是在init/initramfs.c中:

看定義就知道這是這是初始化掛載根文件系統的函數,具體內容自己分析吧,在main.c中start_kernel最後一個函數:rest_init -> kernel_thread -> kernel_init:

914行會執行初始化平臺所有的驅動、總線等設備驅動,還有掛載ramdisk也是在這裡執行,917行打開控制臺,920,921行執行后,標準輸入,標準輸出,錯誤輸出都定向到控制台中,這就是我們串口的輸入輸出了;931行訪問看看/init是否存在,我們這裡ramdisk已經掛在上了,所以存在,如果ramdisk沒有掛載則不存在,會執行935行的prepare_namespace并在該函數中掛載根文件系統;往下到945行init_post:

執行847行后kernel就一去不複返了,進入了framewrok的init程序。

我們回頭看看沒有掛載ramdisk的情況,也就是執行935行的prepare_namespace函數:

386行等待所有設備初始化完成,392行就是我們uboot傳遞進來的bootargs參數:

看112行的mount_initrd值:

意思很明白,默認是有ramdisk的,如果你的uboot參數bootargs中設置了noinitrd,則這裡就為0了;回到prepare_namespace函數中,424行:

338行是floppy設備的,沒有定義,361行mount_block_root函數:

235行,得到存放內核所支持的文件系統類型首地址,這裡支持的類型有ext2 ext3 ext4 cramfs vfat msdos sysv v7 romfs yaffs yaffs2;248行遍歷所有的文件系統類型并嘗試掛載,如果都不成功,走到279行并打印分區信息,提示無法掛載文件系統,這樣系統就掛掉了,看一下log信息:


補充說一下kernel中的__setup和early_param宏定義:

從136行和144行可以知道,這兩個宏定義的都會被編譯進.init.setup段中,看看鏈接腳本arch/arm/kernel/vmlinux.lds:

在kernel代碼中查找了一下,在init/main.c中:

不难看出,kernel启动时候,传进来的字符串line就是启动参数,以"="为分界,比如等号前面为console,则调用setup_func,传进去的值就为等号后面的值如ttyFIQ0,而setup_func指向__setup宏的第一个参数,即为函数地址

在uboot中传递参数如initrd=0x31000000 40M, 0x31000000表示ramdisk起始位置,40M表示ramdisk的大小,则kernel是在init.c中进行解析的:

在init.c中搜素phys_initrd_start,再往下你会发现:

这里也赋值了,所以这里随便用一处的参数就行了,如PV210就没有传递initrd参数


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值