-----如下內容爲從網絡上整理所得------node
主要介紹kernel_init線程(函數),這個線程在rest_init函數中被建立,kernel_init函數將完成設備驅動程序的初始化,並調用init_post函數啓動用戶空間的init進程。程序員
static int __init kernel_init(void * unused) { lock_kernel(); //鎖住內核 set_mems_allowed(node_states[N_HIGH_MEMORY]); //init能夠在任何節點(node)分配到內存頁 set_cpus_allowed_ptr(current, cpu_all_mask); //init能夠在任何CPU上運行. init_pid_ns.child_reaper = current; //把當前進程設爲接受其餘孤兒進程的進程 cad_pid = task_pid(current); /*SMP系統作準備,激活全部CPU,並開始SMP系統的調度*/ smp_prepare_cpus(setup_max_cpus); do_pre_smp_initcalls(); start_boot_trace(); smp_init(); sched_init_smp(); do_basic_setup(); //驅動程序和內核子系統的通常初始化,下面會詳解 //檢查是否有早期用戶空間的init程序。若是有,讓其執行 if (!ramdisk_execute_command)ramdidk_execute_command="/init"; if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) { ramdisk_execute_command = NULL; prepare_namespace(); } //最後調用init_post,啓動進程負責用戶空間的初始化 init_post(); return 0; }
在內核init線程的最後執行了init_post函數,在這個函數中真正啓動了用戶空間進程init,詳解以下:網絡
static noinline int init_post(void) __releases(kernel_lock) { /* need to finish all async __init code before freeing the memory */ async_synchronize_full(); free_initmem(); unlock_kernel(); mark_rodata_ro(); //經過修改頁表,保證只讀數據段爲只讀屬性。大部分構架爲空函數。 system_state = SYSTEM_RUNNING; //設置系統狀態爲運行狀態 numa_default_policy(); //設定NUMA系統的內存訪問策略爲默認 //打開根文件系統中的 /dev/console , 此處不可失敗 if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0) printk(KERN_WARNING "Warning: unable to open an initial console.\n"); /*複製兩次標準輸入(0)的文件描述符 *它是上面打開的/dev/console,也就是系統控制檯): *一個做爲標準輸出(1) *一個做爲標準出錯(2) *如今標準輸入、標準輸出、標準出錯都是/dev/console了。 *這個console在內核啓動參數中能夠配置爲某個串口(ttySn、ttyOn等等), *也能夠是虛擬控制檯(tty0)。 *因此咱們就在串口或者顯示器上看到了以後的系統登陸提示。 **/ (void) sys_dup(0); (void) sys_dup(0); //設置當前進程(init)爲不能夠殺進程(忽略致命的信號) current->signal->flags |= SIGNAL_UNKILLABLE; //若是ramdisk_execute_command有指定的init程序,就執行它。 if (ramdisk_execute_command) { run_init_process(ramdisk_execute_command); printk(KERN_WARNING "Failed to execute %s\n", ramdisk_execute_command); } //若是execute_command有指定的init程序,就執行它。 if (execute_command) { run_init_process(execute_command); printk(KERN_WARNING "Failed to execute %s. Attempting " "defaults...\n", execute_command); } /*在檢查完ramdisk_execute_command和execute_command爲空的狀況下, *順序執行如下初始化程序:若是都沒有找到就打印錯誤信息。 *這也是咱們作系統移植的時候常常碰到的錯誤信息,出現這個信息頗有多是: *一、你的啓動參數配置有問題,經過 指定了init程序,可是沒有找到, * 且默認的那四個程序也不在文件系統中。 *二、文件系統掛載有問題,文件不存在 *三、init程序沒有執行權限 **/ 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."); }
在基本分析完內核啓動流程的以後,還有一個比較重要的初始化函數沒有分析,那就是do_basic_setup。在內核init線程中調用了do_basic_setup,這個函數也作了不少內核和驅動的初始化工做,詳解以下:async
/* * 好了, 設備如今已經初始化完成。 可是尚未一個設備被初始化過, * 可是 CPU 的子系統已經啓動並運行, * 且內存和處理器管理系統已經在工做了。 * * 如今咱們終於能夠開始作一些實際的工做了.. */ static void __init do_basic_setup(void) { rcu_init_sched(); /* needed by module_init stage. */ init_workqueues(); //初始化工做隊列 /*針對SMP系統,初始化內核control group的cpuset子系統。 *若是非SMP,此函數爲空。 *cpuset是在用戶空間中操做cgroup文件系統來執行進程 *與cpu和進程與內存結點之間的綁定。 *本函數將cpus_allowed和mems_allwed更新爲在線的cpu和在線的內存結點, *併爲內存熱插撥註冊了鉤子函數,最後建立一個單線程工做隊列cpuset。 */ cpuset_init_smp(); /*建立一個單線程工做隊列khelper。 *運行的系統中只有一個,主要做用是指定用戶空間的程序路徑和環境變量, *最終運行指定的user space的程序,屬於關鍵線程,不能關閉。 */ usermodehelper_init(); //初始化驅動模型中的各子系統,可見的現象是在/sys中出現的目錄和文件 driver_init(); //在proc文件系統中建立irq目錄,並在其中初始化系統中全部中斷對應的目錄。 init_irq_proc(); /*調用連接到內核中的全部構造函數,也就是連接進.ctors段中的全部函數。 *在內核啓動和模塊掛載時,調用構造函數(gcc生成的類初始化函數)。 *構造函數就是好比用於初始化gcov數據的函數 */ do_ctors(); /*調用全部編譯內核的驅動模塊中的初始化函數。 *這裏就是驅動程序員須要關心的步驟,其中按照各個內核模塊初始化函數 *所自定義的啓動級別(1~7),按順序調用器初始化函數。 *對於同一級別的初始化函數,安裝編譯是連接的順序調用, *也就是和內核Makefile的編寫有關。 * *在編寫內核模塊的時候須要知道這方面的知識,好比你編寫的模塊使用 *的是I2C的API,那你的模塊的初始化函數的級別必須低於I2C子系統 *初始化函數的級別(也就是級別數(1~7)要大於I2C子系統)。 *若是編寫的模塊必須和依賴的模塊在同一級,那就必須注意內核Makefile的修改了。 */ do_initcalls(); }
上面的函數調用了driver_init函數,做用是驅動模型子系統的初始化,對於內核驅動工程師來講比較重要,詳解以下:函數
/** * driver_init - 初始化驅動模型. * * 調用驅動模型初始化函數來初始化它們的子系統。 * 由早期的init/main.c中調用。 */ void __init driver_init(void) { /* These are the core pieces */ /*初始化驅動模型中的部分子系統和kobject: *devices *dev *dev/block *dev/char */ devices_init(); buses_init();//初始化驅動模型中的bus子系統 classes_init();//初始化驅動模型中的class子系統 firmware_init();//初始化驅動模型中的firmware子系統 hypervisor_init();//初始化驅動模型中的hypervisor子系統 /* These are also core pieces, but must come after the * core core pieces. */ platform_bus_init();//初始化驅動模型中的bus/platform子系統 system_bus_init();//初始化驅動模型中的devices/system子系統 cpu_dev_init();//初始化驅動模型中的devices/system/cpu子系統 memory_dev_init();//初始化驅動模型中的devices/system/memory子系統 }