經(jīng)歷了跟體系結(jié)構(gòu)密切相關(guān)的匯編代碼之后,就可以進入C語言編寫的結(jié)構(gòu)無關(guān)的代碼了。
這個入口的函數(shù)是start_kernel函數(shù),它主要更進一步地初始化系統(tǒng)相關(guān)的內(nèi)容,以便系統(tǒng)進入一種服務(wù)狀態(tài),提供一種虛擬機的服務(wù),提供各種API調(diào)用的服務(wù)。
在start_kernel函數(shù)里,需要非常注意的是里面初始化函數(shù)的順序,這些初始化函數(shù)不能隨便調(diào)換初始化順序,否則就會導(dǎo)致系統(tǒng)運行出錯。
由于這個函數(shù)的內(nèi)容非常多,涉及的內(nèi)容也非常廣泛,每個函數(shù)都有一個比較大的概念,一種原理,一種想法。
因此,對于這個函數(shù)的學(xué)習(xí)需要很多時間,需要有漫長學(xué)習(xí)的心理準(zhǔn)備。
由于本書基于ARM體系的一種結(jié)構(gòu)學(xué)習(xí),其它與此體系結(jié)構(gòu)無關(guān)的代碼,就不再分析介紹。好了,現(xiàn)在就來開始學(xué)習(xí)第一節(jié)的內(nèi)容,代碼如下:
asmlinkage void __init start_kernel(void){ char * command_line; extern const struct kernel_param __start___param[], __stop___param[];
看了這段代碼,首先發(fā)現(xiàn)asmlinkage和__init與一般開發(fā)C語言的應(yīng)用程序有著明顯的差別,導(dǎo)致看不懂這兩個宏到底是用來做干什么用的。
其實這兩個宏是寫內(nèi)核代碼的一種特定表示,一種盡可能快的思想表達,一種盡可能占用空間少的思路。
asmlinkage是一個宏定義,它的作用主要有兩個,一個是讓傳送給函數(shù)的參數(shù)全部使用棧式傳送,不用寄存器來傳送。
因為寄存器的個數(shù)有限,使用??梢詡魉透嗟膮?shù),比如在X86的CPU里只能使用6個寄存器傳送,只能傳送4個參數(shù),而使用棧就沒有這種限制;另外一個用處是聲明這個函數(shù)是給匯編代碼調(diào)用的。
不過在ARM體系里,并沒有使用棧傳送參數(shù)的特性,原因何在?由于ARM體系的寄存器個數(shù)比較多,多達13個,這樣絕大多數(shù)的函數(shù)參數(shù)都可以通過寄存器來傳送,達到高效的目標(biāo)。
因此,看到文件./include/linux/linkage.h里的asmlinkage宏定義如下:
#include #include #ifdef __cplusplus#define CPP_ASMLINKAGE extern "C"#else#define CPP_ASMLINKAGE#endif#ifndef asmlinkage#define asmlinkage CPP_ASMLINKAGE#endif#ifndef asmregparm# define asmregparm#endif
在這里可以看到asmlinkage,其實沒有定義,所以ARM體系里還是通過寄存器來傳送參數(shù)的。如果看一下X86下的代碼,就會定義如下:
#ifdef CONFIG_X86_32#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))
這里定義asmlinkage為通過棧傳送參數(shù)。
接著來看另外一個宏定義__init,這個宏定義主要用來標(biāo)志這個函數(shù)編譯出來的目標(biāo)代碼放在那一段里。
對于應(yīng)用程序的編譯和連接,不需要作這樣的考慮,但是對于內(nèi)核代碼來說,就需要了,因為不同的段代碼有著不同的作用,比如初始化段的代碼,當(dāng)系統(tǒng)運行正常以后,這段代碼就沒有什么用了,聰明的做法就是回收這段代碼占用的內(nèi)存,讓內(nèi)核的代碼占最少的內(nèi)存。
還有另外一個作用,比如同一段的代碼都是編譯在一起,讓相關(guān)聯(lián)的代碼盡可能同在一片內(nèi)存里,這樣當(dāng)CPU加載代碼到緩存時,就可以一起命中,提高緩存的命中率,這樣就大大提高代碼的執(zhí)行速度。
宏__init定義在文件./include/linux/init.h里,代碼如下:
/* These are for everybody (although not all archs will actually discard it in modules) */#define __init __section(.init.text) __cold notrace
使用這個宏聲明的函數(shù),編譯時就會把目標(biāo)代碼放到段.init.text里,這段都是放置初始化的代碼。
最后看到聲明一個字符的指針command_line,這個指針是指向命令行參數(shù)的指針,主要用來指向引導(dǎo)程序傳送給內(nèi)核的命令行參數(shù),在后面的函數(shù)setup_arch和函數(shù)setup_command_line就會對它進行處理。
smp_setup_processor_id();
緊跟參數(shù)后面的,就是調(diào)用函數(shù)smp_setup_processor_id()了,這個函數(shù)主要作用是獲取當(dāng)前正在執(zhí)行初始化的處理器ID。
如果仔細地閱讀完初始化函數(shù)start_kernel,就會發(fā)現(xiàn)里面還有調(diào)用smp_processor_id()函數(shù),這兩個函數(shù)都是獲取多處理器的ID,為什么會需要兩個函數(shù)呢?
其實這里有一個差別的,smp_setup_processor_id()函數(shù)可以不調(diào)用setup_arch()初始化函數(shù)就可以使用,而smp_processor_id()函數(shù)是一定要調(diào)用setup_arch()初始化函數(shù)后,才能使用。
smp_setup_processor_id()函數(shù)是直接獲取對稱多處理器的ID,而smp_processor_id()函數(shù)是獲取變量保存的處理器ID,因此一定要調(diào)用初始化函數(shù)。
由于smp_setup_processor_id()函數(shù)不用調(diào)用初始化函數(shù),可以放在內(nèi)核初始化start_kernel函數(shù)的最前面使用,而函數(shù)smp_processor_id()只能放到setup_arch()函數(shù)調(diào)用的后面使用了。
smp_setup_processor_id()函數(shù)每次都要中斷CPU去獲取ID,這樣效率比較低。在這個函數(shù)里,還需要懂得另外一個概念,就是對稱多處理器(SymmetricalMulti-Processing)。
由于單處理器的頻率已經(jīng)慢慢變得不能再高了,那么處理器的計算速度還要提高,還有別的辦法嗎?這樣自然就想到多個處理器的技術(shù)。
這就好比物流公司,有很多貨只讓一輛卡車在高速公路上來回運貨,這樣車的速度已經(jīng)最快了,運的貨就一定了,不可能再多得去。
那么物流公司想提高運貨量,那只能多顧用幾臺卡車了,這樣運貨量就比以前提高了。處理器的制造廠家自然也想到這樣的辦法,就是幾個處理器放到一起,這樣就可以提高處理速度。
接著下來的問題又來,那么這幾個處理器怎么樣放在一起,成本最低,性能最高??紤]到這樣的一種情況,處理器只有共享主內(nèi)存、總線、外圍設(shè)備,其它每個處理器是獨立的,這樣可以省掉很多外圍硬件成本。
當(dāng)然所有這些處理器還共享一個操作系統(tǒng),這樣的結(jié)構(gòu)就叫做對稱多處理器(SymmetricalMulti-Processing)。在對稱多處理器系統(tǒng)里,所有處理器只有在初始化階段處理有主從之分,到系統(tǒng)初始化完成之后,大家是平等的關(guān)系,沒有主從處理器之分了。
在內(nèi)核里所有以smp開頭的函數(shù)都是處理對稱多處理器相關(guān)內(nèi)容的,對稱多處理器與單處理器在操作系統(tǒng)里,主要區(qū)別是引導(dǎo)處理器與應(yīng)用處理器,每個處理器不同的緩存,中斷協(xié)作,鎖的同步。因此,在內(nèi)核初始化階段需要區(qū)分,在與緩存同步數(shù)據(jù)需要處理,在中斷方面需要多個處理協(xié)作執(zhí)行,在多個進程之間要做同步和通訊。如果內(nèi)核只是有單處理器系統(tǒng),smp_setup_processor_id()函數(shù)是是空的,不必要做任保的處理。
/* * Need to run as early as possible, to initialize the * lockdep hash: */ lockdep_init();
這個函數(shù)主要作用是初始化鎖的狀態(tài)跟蹤模塊。由于內(nèi)核大量使用鎖來進行多進程、多處理器的同步操作,那么死鎖就會在代碼不合理時出現(xiàn),這時要知道那個鎖造成的,真是比較困難的。
遇到這種情況,就需要想辦法知道那個鎖造成的,因此就需要跟蹤鎖的使用狀態(tài),以便發(fā)現(xiàn)出錯時,把鎖的狀態(tài)打印出來。
造成死鎖的情況有很多,主要有以下幾種:
1. 同一個進程遞歸地加鎖同一把鎖。
2. 同一把鎖在兩次中斷里加鎖。
3. 幾把鎖形成一個閉環(huán)死鎖。
debug_objects_early_init();
這個函數(shù)主要作用是對調(diào)試對象進行早期的初始化,其實就是HASH鎖和靜態(tài)對象池進行初始化。
/* * Set up the the initial canary ASAP: */ boot_init_stack_canary(); cgroup_init_early();
cgroup_init_early()這個函數(shù)主要作用是控制組進行早期的初始化。
什么叫控制組(controlgroups)呢?簡單地說,控制組就是定義一組進程具有相同資源的占有程度。
比如可以指定一組進程使用CPU為30%,磁盤IO為40%,網(wǎng)絡(luò)帶寬為50%。因此通過控制組就可以把所有進程分配不同的資源。
可以參考這個文檔(http://docs.redhat.com/docs/en-US/Red_Hat_Enterprise_Linux/6/html/Resource_Management_Guide/ch01.html)。
local_irq_disable();
這個函數(shù)主要作用是關(guān)閉當(dāng)前CPU的所有中斷響應(yīng)。在ARM體系里主要就是對CPSR寄存器進行操作。
early_boot_irqs_off();
這個函數(shù)主要作用是標(biāo)記內(nèi)核還在早期初始化代碼階段,并且中斷在關(guān)閉狀態(tài),如果有任何中斷打開或請求中斷的事情出現(xiàn),都是會提出警告,以便跟蹤代碼錯誤情況。
早期代碼初始化結(jié)束之后,就會調(diào)用函數(shù)early_boot_irqs_on來設(shè)置這個標(biāo)志為真。
/* * Interrupts are still disabled. Do necessary setups, then * enable them */ tick_init();
這個函數(shù)主要作用是初始化時鐘事件管理器的回調(diào)函數(shù),比如當(dāng)時鐘設(shè)備添加時處理。
在內(nèi)核里定義了時鐘事件管理器,主要用來管理所有需要周期性地執(zhí)行任務(wù)的設(shè)備。
boot_cpu_init();
這個函數(shù)主要作用是設(shè)置當(dāng)前引導(dǎo)系統(tǒng)的CPU在物理上存在,在邏輯上可以使用,并且初始化準(zhǔn)備好。
在多CPU的系統(tǒng)里,內(nèi)核需要管理多個CPU,那么就需要知道系統(tǒng)有多少個CPU,在內(nèi)核里使用cpu_present_map位圖表達有多少個CPU,每一位表示一個CPU的存在。
如果是單個CPU,就是第0位設(shè)置為1。
雖然系統(tǒng)里有多個CPU存在,但是每個CPU不一定可以使用,或者沒有初始化,在內(nèi)核使用cpu_online_map位圖來表示那些CPU可以運行內(nèi)核代碼和接受中斷處理。
隨著移動系統(tǒng)的節(jié)能需求,需要對CPU進行節(jié)能處理,比如有多個CPU運行時可以提高性能,但花費太多電能,導(dǎo)致電池不耐用,需要減少運行的CPU個數(shù),或者只需要一個CPU運行。
這樣內(nèi)核又引入了一個cpu_possible_map位圖,表示最多可以使用多少個CPU。
在本函數(shù)里就是依次設(shè)置這三個位圖的標(biāo)志,讓引導(dǎo)的CPU物理上存在,已經(jīng)初始化好,最少需要運行的CPU。
page_address_init();
這個函數(shù)主要作用是初始化高端內(nèi)存的映射表。
在這里引入了高端內(nèi)存的概念,那么什么叫做高端內(nèi)存呢?為什么要使用高端內(nèi)存呢?其實高端內(nèi)存是相對于低端內(nèi)存而存在的,那么先要理解一下低端內(nèi)存了。
在32位的系統(tǒng)里,最多能訪問的總內(nèi)存是4G,其中3G空間給應(yīng)用程序,而內(nèi)核只占用1G的空間。
因此,內(nèi)核能映射的內(nèi)存空間,只有1G大小,但實際上比這個還要小一些,大概是896M,另外128M空間是用來映射高端內(nèi)存使用的。
因此0到896M的內(nèi)存空間,就叫做低端內(nèi)存,而高于896M的內(nèi)存,就叫高端內(nèi)存了。
如果系統(tǒng)是64位系統(tǒng),當(dāng)然就沒未必要有高端內(nèi)存存在了,因為64位有足夠多的地址空間給內(nèi)核使用,訪問的內(nèi)存可以達到10G都沒有問題。
在32位系統(tǒng)里,內(nèi)核為了訪問超過1G的物理內(nèi)存空間,需要使用高端內(nèi)存映射表。
比如當(dāng)內(nèi)核需要讀取1G的緩存數(shù)據(jù)時,就需要分配高端內(nèi)存來使用,這樣才可以管理起來。
使用高端內(nèi)存之后,32位的系統(tǒng)也可以訪問達到64G內(nèi)存。
在移動操作系統(tǒng)里,目前還沒有這個必要,最多才1G多內(nèi)存。
printk(KERN_NOTICE "%s", linux_banner);
這行代碼主要作用是在輸出終端上顯示版本信息、編譯的電腦用戶名稱、編譯器版本、編譯時間。如下所示:
Linuxversion 2.6.37+ (tony@tony-desktop) (gcc version 4.3.3 (Sourcery G++Lite 2009q1-203) ) #40 Tue Mar 20 17:49:58 CST 2012
linux_banner是在文件kernel/init/version.c里定義,這個字符串是由編譯腳本自動生成。
setup_arch(&command_line);
這個函數(shù)主要作用是對內(nèi)核架構(gòu)進行初始化。
再次獲取CPU類型和系統(tǒng)架構(gòu),分析引導(dǎo)程序傳入的命令行參數(shù),進行頁面內(nèi)存初始化,處理器初始化,中斷早期初始化等等。
mm_init_owner(&init_mm, &init_task);
這個函數(shù)主要作用是設(shè)置最開始的初始化任務(wù)屬于init_mm內(nèi)存。在ARM里,這個函數(shù)為空。
setup_command_line(command_line);
這個函數(shù)主要作用是保存命令行,以便后面可以使用。
setup_nr_cpu_ids();
這個函數(shù)主要作用是設(shè)置最多有多少個nr_cpu_ids結(jié)構(gòu)。
setup_per_cpu_areas();
這個函數(shù)主要作用是設(shè)置SMP體系每個CPU使用的內(nèi)存空間,同時拷貝初始化段里數(shù)據(jù)。
smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */
這個函數(shù)主要作用是為SMP系統(tǒng)里引導(dǎo)CPU進行準(zhǔn)備工作。在ARM系統(tǒng)單核里是空函數(shù)。
build_all_zonelists(NULL);
這個函數(shù)主要作用是初始化所有內(nèi)存管理節(jié)點列表,以便后面進行內(nèi)存管理初始化。
page_alloc_init();
這個函數(shù)主要作用是設(shè)置內(nèi)存頁分配通知器。
printk(KERN_NOTICE "Kernel command line: %s ", boot_command_line);
這行代碼主要作用是輸出命令參數(shù)到顯示終端。
parse_early_param();
這個函數(shù)主要作用是分析命令行最早使用的參數(shù)。
parse_args("Booting kernel", static_command_line, __start___param, __stop___param - __start___param, &unknown_bootoption);
這行代碼主要對傳入內(nèi)核參數(shù)進行解釋,如果不能識別的命令就調(diào)用最后參數(shù)的函數(shù)。
/* * These use large bootmem allocations and must precede * kmem_cache_init() */ pidhash_init();
這個函數(shù)是進程ID的HASH表初始化,這樣可以提供通PID進行高效訪問進程結(jié)構(gòu)的信息。
LINUX里共有四種類型的PID,因此就有四種HASH表相對應(yīng)。
vfs_caches_init_early();
這個函數(shù)是虛擬文件系統(tǒng)的緩存初始化。
sort_main_extable();
這個函數(shù)是對內(nèi)核內(nèi)部的異常表進行堆排序,以便加速訪問。
trap_init();
這個函數(shù)是對異常進行初始化,在ARM系統(tǒng)里是空函數(shù),沒有任何的初始化。
mm_init();
這個函數(shù)是標(biāo)記那些內(nèi)存可以使用,并且告訴系統(tǒng)有多少內(nèi)存可以使用,當(dāng)然是除了內(nèi)核使用的內(nèi)存以外。
/* * Set up the scheduler prior starting any interrupts (such as the * timer interrupt). Full topology setup happens at smp_init() * time - but meanwhile we still have a functioning scheduler. */ sched_init();
這個函數(shù)主要作用是對進程調(diào)度器進行初始化,比如分配調(diào)度器占用的內(nèi)存,初始化任務(wù)隊列,設(shè)置當(dāng)前任務(wù)的空線程,當(dāng)前任務(wù)的調(diào)度策略為CFS調(diào)度器。
/* * Disable preemption - early bootup scheduling is extremely * fragile until we cpu_idle() for the first time. */ preempt_disable();
這個函數(shù)主要作用是關(guān)閉優(yōu)先級調(diào)度。由于每個進程任務(wù)都有優(yōu)先級,目前系統(tǒng)還沒有完全初始化,還不能打開優(yōu)先級調(diào)度。
if (!irqs_disabled()) { printk(KERN_WARNING "start_kernel(): bug: interrupts were " "enabled *very* early, fixing it "); local_irq_disable(); }
這段代碼主要判斷是否過早打開中斷,如果是這樣,就會提示,并把中斷關(guān)閉。
rcu_init();
這個函數(shù)是初始化直接讀拷貝更新的鎖機制。
RCU主要提供在讀取數(shù)據(jù)機會比較多,但更新比較的少的場合,這樣減少讀取數(shù)據(jù)鎖的性能低下的問題。
radix_tree_init();
這個函數(shù)是初始化radix樹,radix樹基于二進制鍵值的查找樹。
/* init some links before init_ISA_irqs() */ early_irq_init();
init_IRQ();
這個函數(shù)是初始化中斷相關(guān)的工作,主要初始化中斷描述數(shù)組,然后調(diào)用每個CPU架構(gòu)中斷初始化。
prio_tree_init();
這個函數(shù)是初始化優(yōu)先搜索樹,主要用在內(nèi)存反向搜索方面。
init_timers();
這個函數(shù)是主要初始化引導(dǎo)CPU的時鐘相關(guān)的數(shù)據(jù)結(jié)構(gòu),注冊時鐘的回調(diào)函數(shù),當(dāng)時鐘到達時可以回調(diào)時鐘處理函數(shù),最后初始化時鐘軟件中斷處理。
hrtimers_init();
這個函數(shù)是初始化高精度的定時器,并設(shè)置回調(diào)函數(shù)。
softirq_init();
這個函數(shù)是初始化軟件中斷,軟件中斷與硬件中斷區(qū)別就是中斷發(fā)生時,軟件中斷是使用線程來監(jiān)視中斷信號,而硬件中斷是使用CPU硬件來監(jiān)視中斷。
timekeeping_init();
這個函數(shù)是初始化系統(tǒng)時鐘計時,并且初始化內(nèi)核里與時鐘計時相關(guān)的變量。
time_init();
這個函數(shù)是初始化系統(tǒng)時鐘。
profile_init();
這個函數(shù)是分配內(nèi)核性能統(tǒng)計保存的內(nèi)存,以便統(tǒng)計的性能變量可以保存到這里。
if (!irqs_disabled()) printk(KERN_CRIT "start_kernel(): bug: interrupts were " "enabled early ");
這兩行代碼是提示中斷是否過早地打開。
early_boot_irqs_on();
這個函數(shù)是設(shè)置內(nèi)核還在早期初始化階段的標(biāo)志,以便用來調(diào)試時輸出信息。
local_irq_enable();
這個函數(shù)是打開本CPU的中斷,也即允許本CPU處理中斷事件,在這里打開引CPU的中斷處理。如果有多核心,別的CPU還沒有打開中斷處理。
/* Interrupts are enabled now so all GFP allocations are safe. */ gfp_allowed_mask = __GFP_BITS_MASK; kmem_cache_init_late();
/* * HACK ALERT! This is early. We're enabling the console before * we've done PCI setups etc, and console_init() must be aware of * this. But we do want output early, in case something goes wrong. */ console_init();
這個函數(shù)是用來初始化控制臺,從這個函數(shù)之后就可以輸出內(nèi)容到控制臺了。
在這個函數(shù)初化之前,都沒有辦法輸出內(nèi)容,就是輸出,也是寫到輸出緩沖區(qū)里,緩存起來,等到這個函數(shù)調(diào)用之后,就立即輸出內(nèi)容。
if (panic_later) panic(panic_later, panic_param);
這段代碼是判斷分析輸入的參數(shù)是否出錯,如果有出錯,就啟動控制臺輸出之后,立即打印出錯的參數(shù),以便用戶立即看到出錯的地方。
lockdep_info();
這個函數(shù)是打印鎖的依賴信息,用來調(diào)試鎖。通過這個函數(shù)可以查看目前鎖的狀態(tài),以便可以發(fā)現(xiàn)那些鎖產(chǎn)生死鎖,那些鎖使用有問題。
/* * Need to run this when irqs are enabled, because it wants * to self-test [hard/soft]-irqs on/off lock inversion bugs * too: */ locking_selftest();
這個函數(shù)是用來測試鎖的API是否使用正常,進行自我測試。比如測試自旋鎖、讀寫鎖、一般信號量和讀寫信號量。
#ifdef CONFIG_BLK_DEV_INITRD if (initrd_start && !initrd_below_start_ok && page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) { printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - " "disabling it. ", page_to_pfn(virt_to_page((void *)initrd_start)), min_low_pfn); initrd_start = 0; }#endif page_cgroup_init();
page_cgroup_init()這個函數(shù)是容器組的頁面內(nèi)存分配。
enable_debug_pagealloc();
這個函數(shù)是設(shè)置內(nèi)存分配是否需要輸出調(diào)試信息,如果調(diào)用這個函數(shù),當(dāng)分配內(nèi)存時,不會輸出一些相關(guān)的信息。
kmemleak_init();
debug_objects_mem_init();
這個函數(shù)是創(chuàng)建調(diào)試對象內(nèi)存緩存,所以緊跟內(nèi)存緩存初始化后面
idr_init_cache();
這個函數(shù)是創(chuàng)建IDR機制的內(nèi)存緩存對象。所謂的IDR就是整數(shù)標(biāo)識管理機制(integerIDmanagement)。
引入的主要原因是管理整數(shù)的ID與對象的指針的關(guān)系,由于這個ID可以達到32位,也就是說,如果使用線性數(shù)組來管理,那么分配的內(nèi)存太大了;如果使用線性表來管理,又效率太低了,所以就引用IDR管理機制來實現(xiàn)這個需求。
setup_per_cpu_pageset();
這個函數(shù)是創(chuàng)建每個CPU的高速緩存集合數(shù)組。因為每個CPU都不定時需要使用一些頁面內(nèi)存和釋放頁面內(nèi)存,為了提高效率,就預(yù)先創(chuàng)建一些內(nèi)存頁面作為每個CPU的頁面集合。
numa_policy_init();
這個函數(shù)是初始化NUMA的內(nèi)存訪問策略。所謂NUMA,它是NonUniform Memory AccessAchitecture的縮寫,主要用來提高多個CPU訪問內(nèi)存的速度。因為多個CPU訪問同一個節(jié)點的內(nèi)存速度遠遠比訪問多個節(jié)點的速度來得快。
if (late_time_init) late_time_init();
這段代碼是主要運行時鐘相關(guān)后期的初始化功能。
sched_clock_init();
calibrate_delay();
這個函數(shù)是主要計算CPU需要校準(zhǔn)的時間,這里說的時間是CPU執(zhí)行時間。如果是引導(dǎo)CPU,這個函數(shù)計算出來的校準(zhǔn)時間是不需要使用的,主要使用在非引導(dǎo)CPU上,因為非引導(dǎo)CPU執(zhí)行的頻率不一樣,導(dǎo)致時間計算不準(zhǔn)確。
pidmap_init();
這個函數(shù)是進程位圖初始化,一般情況下使用一頁來表示所有進程占用情況。
anon_vma_init();
這個函數(shù)是初始化反向映射的匿名內(nèi)存,提供反向查找內(nèi)存的結(jié)構(gòu)指針位置,快速地回收內(nèi)存。
#ifdef CONFIG_X86 if (efi_enabled) efi_enter_virtual_mode();#endif
這段代碼是初始化EFI的接口,并進入虛擬模式。EFI是ExtensibleFirmware Interface的縮寫,就是INTEL公司新開發(fā)的BIOS接口。
thread_info_cache_init();
這個函數(shù)是線程信息的緩存初始化。
cred_init();
fork_init(totalram_pages);
這個函數(shù)是根據(jù)當(dāng)前物理內(nèi)存計算出來可以創(chuàng)建進程(線程)的數(shù)量,并進行進程環(huán)境初始化。
proc_caches_init();
這個函數(shù)是進程緩存初始化。
buffer_init();
這個函數(shù)是初始化文件系統(tǒng)的緩沖區(qū),并計算最大可以使用的文件緩存。
key_init();
這個函數(shù)是初始化安全鍵管理列表和結(jié)構(gòu)。
security_init();
這個函數(shù)是初始化安全管理框架,以便提供訪問文件/登錄等權(quán)限。
dbg_late_init();
vfs_caches_init(totalram_pages);
這個函數(shù)是虛擬文件系統(tǒng)進行緩存初始化,提高虛擬文件系統(tǒng)的訪問速度。
signals_init();
這個函數(shù)是初始化信號隊列緩存。
/* rootfs populating might need page-writeback */ page_writeback_init();
#ifdef CONFIG_PROC_FS proc_root_init();#endif
這個函數(shù)是初始化系統(tǒng)進程文件系統(tǒng),主要提供內(nèi)核與用戶進行交互的平臺,方便用戶實時查看進程的信息。
cgroup_init();
這個函數(shù)是初始化進程控制組,主要用來為進程和其子程提供性能控制。比如限定這組進程的CPU使用率為20%。
cpuset_init();
這個函數(shù)是初始化CPUSET,CPUSET主要為控制組提供CPU和內(nèi)存節(jié)點的管理的結(jié)構(gòu)。
taskstats_init_early();
這個函數(shù)是初始化任務(wù)狀態(tài)相關(guān)的緩存、隊列和信號量。任務(wù)狀態(tài)主要向用戶提供任務(wù)的狀態(tài)信息。
delayacct_init();
這個函數(shù)是初始化每個任務(wù)延時計數(shù)。當(dāng)一個任務(wù)等CPU運行,或者等IO同步時,都需要計算等待時間。
check_bugs();
這個函數(shù)是用來檢查CPU配置、FPU等是否非法使用不具備的功能。
acpi_early_init(); /* before LAPIC and SMP init */
這個函數(shù)是初始化ACPI電源管理。
高級配置與能源接口(ACPI)ACPI規(guī)范介紹ACPI能使軟、硬件、操作系統(tǒng)(OS),主機板和外圍設(shè)備,依照一定的方式管理用電情況,系統(tǒng)硬件產(chǎn)生的Hot-Plug事件,讓操作系統(tǒng)從用戶的角度上直接支配即插即用設(shè)備,不同于以往直接通過基于BIOS 的方式的管理。
sfi_init_late();
ftrace_init();
這個函數(shù)是初始化內(nèi)核跟蹤模塊,ftrace的作用是幫助開發(fā)人員了解Linux?內(nèi)核的運行時行為,以便進行故障調(diào)試或性能分析。
/* Do the rest non-__init'ed, we're now alive */ rest_init();}
這個函數(shù)是后繼初始化,主要是創(chuàng)建內(nèi)核線程init,并運行。
?
評論
查看更多