其實對核心的代碼已經分析很久了,早就想自己寫些什麼,從今天開始,從新繼續我的部落格!
這幾年都在與Linux打交道了,而且我覺得我也真正的愛上了Linux,所以就寫些Linux的東西吧!
Linux的東西很多,就核心而言,已經無法一個人去瞭解所有的機制和細節了。但好在源碼是可以隨時取到的,只要你熟悉和瞭解核心的一些基本特性,還是可以很容易上手的!
下面,我就把我自己的一些學習經曆寫出來和大家分享一下!
首選,核心代碼裡有大小寫重名的檔案,所以,從網上下載了核心源碼包以後,不能直接在Windows下解壓,否則會有些檔案被大小寫重複的檔案名稱複蓋掉!主要是網路相關的。我暫時先不想瞭解網路相關的內容,所以,就先在Windows下,使用SourceInsight來看代碼!如果要看到全部的代碼,還是要在Linux系統下解壓代碼!
另外,我對X86體繫結構的代碼也暫時不感興趣,先從ARM入手,不過不同的體繫結構,關係並不太大,明白一些機制以後,大部份是一樣的!
先從第一個函數入手:
E:\Projects\kernel\linux-2.6.21.1.src\init\main.c (501/825)
asmlinkage void __init start_kernel(void);
這個函數是核心由引導程式引導以後,由自解壓程式解壓以後執行的第一個函數,可以認為是整個核心的入口函數,以後我分析的代碼全部從這個函數開始!
這個函數做的事情相對比較簡單,就是線性初始化一些核心的基礎機制,如中斷,記憶體管理,進程管理,訊號,檔案系統,KO等!最後就啟動一個init線程,init線程再讀取檔案系統裡的init程式,做為系統的第一個進程而存在!
其實,start_kernel函數是0是做為0號進程存在的,它在最後就是空轉CPU:
代碼
/*
* The idle thread. We try to conserve power, while trying to keep
* overall latency low. The architecture specific idle is passed
* a value to indicate the level of "idleness" of the system.
*/
void cpu_idle(void)
{
local_fiq_enable();
/* endless idle loop with no priority at all */
while (1) {
void (*idle)(void) = pm_idle;
#ifdef CONFIG_HOTPLUG_CPU
if (cpu_is_offline(smp_processor_id())) {
leds_event(led_idle_start);
cpu_die();
}
#endif
if (!idle)
idle = default_idle;
leds_event(led_idle_start);
while (!need_resched())
idle();
leds_event(led_idle_end);
preempt_enable_no_resched();
schedule();
preempt_disable();
}
}
而在它之前,啟動的init線程,則是運行檔案系統裡的init程式:
代碼
/* This is a non __init function. Force it to be noinline otherwise gcc
* makes it inline to init() and it becomes part of init.text section
*/
static int noinline init_post(void)
{
free_initmem();
unlock_kernel();
mark_rodata_ro();
system_state = SYSTEM_RUNNING;
numa_default_policy();
if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
printk(KERN_WARNING "Warning: unable to open an initial console.\n");
(void) sys_dup(0);
(void) sys_dup(0);
if (ramdisk_execute_command) {
run_init_process(ramdisk_execute_command);
printk(KERN_WARNING "Failed to execute %s\n",
ramdisk_execute_command);
}
/*
* We try each of these until one succeeds.
*
* The Bourne shell can be used instead of init if we are
* trying to recover a really broken machine.
*/
if (execute_command) { /* 如果有啟動參數做為執行命令,就執行 */
run_init_process(execute_command);
printk(KERN_WARNING "Failed to execute %s. Attempting "
"defaults...\n", execute_command);
} /* 依次查詢檔案系統裡的init程式,這裡的run_init_process函數不能返回,否則啟動失敗 */
run_init_process("/sbin/init");
run_init_process("/etc/init");
run_init_process("/bin/init");
run_init_process("/bin/sh");
panic("No init found. Try passing init= option to kernel.");
}
因為核心為很多體繫結構的CPU實現具體的函數,所以一個函數可能在很多目錄裡的同名檔案所實現。在查詢是具體的哪個函數時,要對應的具體的體繫結構。如果對應的具體體繫結構裡沒有相關函數,就可在使用通用的函數或者通用的體繫結構裡的函數!