?? linux啟動分析.txt
字號:
引導Linux通常有兩種方法,一種是由MILO及其他類似的引導程序引導,另一種是由Firmware直接引導。
“arch/alpha/boot”下就是制作Linux Bootloader的文件?!癶ead.S”文件提供了對 OSF PAL/1的調用入口,它將被編譯后置于引導扇區(ARC的分區首扇區或SRM的磁盤0扇區),得到控制后初始化一些數據結構,再將控制轉給“main.c”中的start_kernel(), start_kernel()向控制臺輸出一些提示,調用pal_init()初始化PAL代碼,調用openboot() 打開引導設備(通過讀取Firmware環境),調用load()將核心代碼加載到START_ADDR(見 “include/asm-alpha/system.h”),再將Firmware中的核心引導參數加載到ZERO_PAGE(0) 中,最后調用runkernel()將控制轉給0x100000的kernel,bootloader部分結束。
“arch/alpha/boot/bootp.c”以“main.c”為基礎,可代替“main.c”與“head.S” 生成用于BOOTP協議網絡引導的Bootloader。
Bootloader中使用的所有“srm_”函數在“arch/alpha/lib/”中定義。
以上這種Boot方式是一種最簡單的方式,即不需其他工具就能引導Kernel,前提是按照 Makefile的指導,生成bootimage文件,內含以上提到的bootloader以及vmlinux,然后將 bootimage寫入自磁盤引導扇區始的位置中。
當采用MILO這樣的引導程序來引導Linux時,不需要上面所說的Bootloader,而只需要 vmlinux或vmlinux.gz,引導程序會主動解壓加載內核到0x1000(小內核)或0x100000(大內核),并直接進入內核引導部分,
bbbbbbbbbbbbbbbbbbbbbbb
arch/alpha/vmlinux.lds的鏈接腳本控制下,鏈接程序將vmlinux的入口置于 "arch/alpha/kernel/head.S"中
的__start上,因此當Bootloader跳轉到0x100000時, __start處的代碼開始執行。__start的代碼很簡單,
只需要設置一下全局變量,然后就跳轉到start_kernel去了。
start_kernel()是"/init/main.c"(體系結構無關)中的asmlinkage函數。
至此,啟動過程轉入體系結構無關的通用C代碼中。
--> 對arm平臺
arch/arm/kernel/head-armv.s(32bit)(head-armo.s(26bit))
里面有一句add pc, r10, #12
r10=__proc_info_end(腳本里面定義arch\arm\vmlinux-armo.lds.in(17))
里面包含arm\mm\proc-arm920.S(645)
r10調整12就是指向結構體里面的一個一條語句 b __arm920_setup
--<
start_kernel()中調用了一系列初始化函數,以完成kernel本身的設置。這些動作有的是公共的,有的則是需要配置的才會執行的。
在start_kernel()函數中,
輸出Linux版本信息(printk(linux_banner))
設置與體系結構相關的環境(setup_arch())
頁表結構初始化(paging_init())
使用"arch/alpha/kernel/entry.S"中的入口點設置系統自陷入口(trap_init())
使用alpha_mv結構和entry.S入口初始化系統IRQ(init_IRQ())
核心進程調度器初始化(包括初始化幾個缺省的Bottom-half,sched_init())
時間、定時器初始化(包括讀取CMOS時鐘、估測主頻、初始化定時器中斷等,time_init())
提取并分析核心啟動參數(從環境變量中讀取參數,設置相應標志位等待處理,(parse_options())
控制臺初始化(為輸出信息而先于PCI初始化,console_init())
剖析器數據結構初始化(prof_buffer和prof_len變量)
核心Cache初始化(描述Cache信息的Cache,kmem_cache_init())
延遲校準(獲得時鐘jiffies與CPU主頻ticks的延遲,calibrate_delay())
內存初始化(設置內存上下界和頁表項初始值,mem_init())
創建和設置內部及通用cache("slab_cache",kmem_cache_sizes_init())
創建uid taskcount SLAB cache("uid_cache",uidcache_init())
創建文件cache("files_cache",filescache_init())
創建目錄cache("dentry_cache",dcache_init())
創建與虛存相關的cache("vm_area_struct","mm_struct",vma_init())
塊設備讀寫緩沖區初始化(同時創建"buffer_head"cache用戶加速訪問,buffer_init())
創建頁cache(內存頁hash表初始化,page_cache_init())
創建信號隊列cache("signal_queue",signals_init())
初始化內存inode表(inode_init())
創建內存文件描述符表("filp_cache",file_table_init())
檢查體系結構漏洞(對于alpha,此函數為空,check_bugs())
SMP機器其余CPU(除當前引導CPU)初始化(對于沒有配置SMP的內核,此函數為空,smp_init())
啟動init過程(創建第一個核心線程,調用init()函數,原執行序列調用cpu_idle() 等待調度,rest_init())
至此start_kernel()結束,基本的核心環境已經建立起來了。
/init/main.c中
init()函數作為核心線程,首先鎖定內核(僅對SMP機器有效),
然后調用 do_basic_setup()完成外設及其驅動程序的加載和初始化。過程如下:
do_basic_setup:
總線初始化(比如pci_init())
網絡初始化(初始化網絡數據結構,包括sk_init()、skb_init()和proto_init()三部分,在proto_init()中,將調用protocols結構中包含的所有協議的初始化過程,sock_init())
創建bdflush核心線程(bdflush()過程常駐核心空間,由核心喚醒來清理被寫過的內存緩沖區,當bdflush()由kernel_thread()啟動后,它將自己命名為kflushd)
創建kupdate核心線程(kupdate()過程常駐核心空間,由核心按時調度執行,將內存緩沖區中的信息更新到磁盤中,更新的內容包括超級塊和inode表)
設置并啟動核心調頁線程kswapd(為了防止kswapd啟動時將版本信息輸出到其他信息中間,核心線調用kswapd_setup()設置kswapd運行所要求的環境,然后再創建 kswapd核心線程)
創建事件管理核心線程(start_context_thread()函數啟動context_thread()過程,并重命名為keventd)
設備初始化(包括并口parport_init()、字符設備chr_dev_init()、塊設備 blk_dev_init()、SCSI設備scsi_dev_init()、網絡設備net_dev_init()、磁盤初始化及分區檢查等等,device_setup())
執行文件格式設置(binfmt_setup())
啟動任何使用__initcall標識的函數(方便核心開發者添加啟動函數,do_initcalls())
文件系統初始化(filesystem_setup())
//安裝root文件系統(mount_root())
至此do_basic_setup()函數返回init(),在釋放啟動內存段(free_initmem())并給內核解鎖以后,init()打開/dev/console設備,重定向stdin、stdout和stderr到控制臺,最后,搜索文件系統中的init程序(或者由init=命令行參數指定的程序),并使用 execve()系統調用加載執行init程序。
prepare_namespace
init()函數到此結束,內核的引導部分也到此結束了,這個由start_kernel()創建的第一個線程已經成為一個用戶模式下的進程了。此時系統中存在著六個運行實體:
start_kernel()本身所在的執行體,這其實是一個"手工"創建的線程,它在創建了init()線程以后就進入cpu_idle()循環了,它不會在進程(線程)列表中出現
init線程,由start_kernel()創建,當前處于用戶態,加載了init程序
kflushd核心線程,由init線程創建,在核心態運行bdflush()函數
kupdate核心線程,由init線程創建,在核心態運行kupdate()函數
kswapd核心線程,由init線程創建,在核心態運行kswapd()函數
keventd核心線程,由init線程創建,在核心態運行context_thread()函數
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -