前置:這裏使用的linux版本是4.8,x86體系。html
其實linux的內核啓動的入口文件仍是很是好找的,init/main.c。linux
首先理解的是static和extern的區別:緩存
static int kernel_init(void *); extern void init_IRQ(void); extern void fork_init(void); extern void radix_tree_init(void);
這個代碼說的是kernel_init函數的定義在這個文件中,extern說明init_IRQ函數的定義在其餘文件中。
這三個extern分別是對中斷的初始化,對fork功能的初始化,對基數樹的初始化。不過具體不知道爲何有的函數以init_xxx爲風格,有的又以xxx_init的風格來作。數據結構
main的第一行看到了這麼個語句函數
#define DEBUG
感受有點奇怪,原來還有#define <宏名> 而沒有定義具體的值。其實這個能夠看成已經有定義,且定義了空串來理解。
http://bbs.csdn.net/topics/390960776?page=1
.net
繼續往下面看,還會看到插件
bool early_boot_irqs_disabled __read_mostly;code
這裏最後的__read_mostly 是一個宏,它標記了前面這個變量是很常常被讀取的。那麼作了標記有什麼用呢?htm
若是在有緩存的平臺上,它就能把這個變量存放到cache中,以保證後續讀取的速度。這個宏定義在 arch/arm/include/asm/cache.hblog
#define __read_mostly __attribute__((__section__(".data..read_mostly")))
這裏的意思是將這個數據結構連接進data.read_mostly段。
EXPORT_SYMBOL(system_state);
這個是和extern一塊兒使用的,表示system_state這個方法在這個模塊中定義了,提供給其餘模塊使用。
在其餘模塊中,只須要使用extern 就可使用這個方法。
這裏就涉及到模塊的概念。
模塊是linux內核對外提供的一個插件機制,因爲linux是單內核,這個單內核是相對微內核來講的。因此linux很大可能會很是龐大,這個模塊機制就是對單內核的一種補充,把一些功能放給內核模塊開發。好比像上面的那個代碼,就是對內核提供了system_state的函數接口。
下面代碼:
char __initdata boot_command_line[COMMAND_LINE_SIZE];
這裏的__initdata也是一個宏,定義在include/linux/init.h
#define __init __section(.init.text) __cold notrace #define __initdata __section(.init.data) #define __initconst __constsection(.init.rodata) #define __exitdata __section(.exit.data) #define __exit_call __used __section(.exitcall.exit)
同上面__read_mostly同樣,是用來把這個變量綁定在某個區裏面。
http://blog.csdn.net/beatbean/article/details/8448623
這個圖就說明了什麼是__section。它的功能有點像是全局變量,只是這個全局變量是對彙編這個層次的表達,某個變量,我固定在某個內存段裏面。這麼作其實還有一個好處,段也是一種分類,好比這個段存儲的是init函數的變量,那麼等初始化結束以後,我把這個段的內存直接釋放。裏面的變量也一次性消除了。
下面看到一個很奇怪的方法
EXPORT_SYMBOL_GPL(static_key_initialized);
這個和以前的EXPORT_SYMBOL不同,多了一個GPL後綴。
因爲模塊頗有多是第三方(非linux內核組成員)開發的。那麼有人但願本身開發的模塊是閉源的。它就會在本身開發的模塊裏面使用
MODULE_LICENSE("Proprietary")
來標記這個模塊是閉源的。相對的,若是你的模塊遵循GPL這個開源許可證規則,那麼則增長下面的:
MODULE_LICENSE("GPL");
好了,linux對這兩種許可證行爲的模塊開放的接口並不相同,本節的這個函數就是說明這個方法只對GPL的模塊開放。
http://www.ruanyifeng.com/blog/2010/02/why_gpl_is_a_better_choice.html
unsigned int reset_devices;
EXPORT_SYMBOL(reset_devices);
static int __init set_reset_devices(char *str)
{
reset_devices = 1;
return 1;
}
__setup("reset_devices", set_reset_devices);
這段代碼,首先須要理解__setup,這個函數就理解爲:啓動時候若是有接收reset_devices參數,那麼就調用set_reset_devices方法。而詳細看了下set_reset_devices方法,裏面只是把reset_devices變量設置爲1,可是呢,這個reset_devices變量又是一個給全部模塊使用的變量。
因此這段代碼能達到的功能是隻要啓動參數有包含reset_device,經過設置reset_devices通知給全部模塊。
與__setup相對應的還有一個叫作early_param。這兩個宏函數的功能同樣,區別就在於early_param定義的參數比__setup更早。