標籤:des blog http 使用 os io 檔案 資料
head-common.S
---具體做了哪些動作
---跳轉到init/main.c
---b start_kernel
//關於start_kernel的強文深入理解linux核心,第八章
main.c
asmlinkage void __init start_kernel(void)
{
char * command_line;
extern struct kernel_param __start___param[], __stop___param[];
//來設定smp process id,當然目前看到的代碼裡面這裡是空的
smp_setup_processor_id();
/*
* Need to run as early as possible, to initialize the
* lockdep hash:
*/
//lockdep是linux核心的一個調試模組,用來檢查核心互斥機制尤其是自旋鎖潛在的死結問題。
//自旋鎖由於是查詢方式等待,不釋放處理器,比一般的互斥機制更容易死結,
//故引入lockdep檢查以下幾種情況可能的死結(lockdep將有專門的文章詳細介紹,在此只是簡單列舉):
//
//·同一個進程遞迴地加鎖同一把鎖;
//
//·一把鎖既在中斷(或中斷下半部)使能的情況下執行過加鎖操作,
// 又在中斷(或中斷下半部)裡執行過加鎖操作。這樣該鎖有可能在鎖定時由於中斷髮生又試圖在同一處理器上加鎖;
//
//·加鎖後導致依賴圖產產生閉環,這是典型的死結現象。
lockdep_init();
debug_objects_early_init();
/*
* Set up the the initial canary ASAP:
*/
//初始化stack_canary棧3
//stack_canary的是帶防止棧溢出攻擊保護的堆棧。
// 當user space的程式通過int 0x80進入核心空間的時候,CPU自動完成一次堆棧切換,
//從user space的stack切換到kernel space的stack。
// 在這個進程exit之前所發生的所有系統調用所使用的kernel stack都是同一個。
//kernel stack的大小一般為4096/8192,
//核心堆棧協助大家理解:
//
// 記憶體低址 記憶體高址
// | |<-----------------------------esp|
// +-----------------------------------4096-------------------------------+
// | 72 | 4 | x < 4016 | 4 |
// +------------------+-----------------+---------------------------------+
// |thread_info | | STACK_END_MAGIC | var/call chain |stack_canary |
// +------------------+-----------------+---------------------------------+
// | 28 | 44 | | |
// V | |
// restart_block V
//
//esp+0x0 +0x40
// +---------------------------------------------------------------------------+
// |ebx|ecx|edx|esi|edi|ebp|eax|ds|es|fs|gs|orig_eax|eip|cs|eflags|oldesp|oldss|
// +---------------------------------------------------------------------------+
// | kernel完成 | cpu自動完成 |
//http://hi.baidu.com/wzt85/blog/item/112a37132f6116c2f6039e44.html
boot_init_stack_canary();
//cgroup: 它的全稱為control group.即一組進程的行為控制.
//比如,我們限制進程/bin/sh的CPU使用為20%.我們就可以建一個cpu佔用為20%的cgroup.
//然後將/bin/sh進程添加到這個cgroup中.當然,一個cgroup可以有多個進程.
//http://blogold.chinaunix.net/u1/51562/showart_1736813.html
cgroup_init_early();
//更新kernel中的所有的立即數值,但是包括哪些需要再看?
core_imv_update();
//關閉當前CUP中斷
local_irq_disable();
//修改標記early_boot_irqs_enabled;
//通過一個靜態全域變數 early_boot_irqs_enabled來協助我們調試代碼,
//通過這個標記可以協助我們知道是否在”early bootup code”,也可以通過這個標誌警告是有無效的終端開啟
early_boot_irqs_off();
//每一個中斷都有一個IRQ描述符(struct irq_desc)來進行描述。
//這個函數的主要作用是設定所有的 IRQ描述符(struct irq_desc)的鎖是統一的鎖,
//還是每一個IRQ描述符(struct irq_desc)都有一個小鎖。
early_init_irq_lock_class();
/*
* Interrupts are still disabled. Do necessary setups, then
* enable them
*/
// 大核心鎖(BKL--Big Kernel Lock)
//大核心鎖本質上也是自旋鎖,但是它又不同於自旋鎖,自旋鎖是不可以遞迴獲得鎖的,因為那樣會導致死結。
//但大核心鎖可以遞迴獲得鎖。大核心鎖用於保護整個核心,而自旋鎖用於保護非常特定的某一共用資源。
//進程保持大核心鎖時可以發生調度,具體實現是:
//在執行schedule時,schedule將檢查進程是否擁有大核心鎖,如果有,它將被釋放,以致於其它的進程能夠獲得該鎖,
//而當輪到該進程運行時,再讓它重新獲得大核心鎖。注意在保持自旋鎖期間是不運行發生調度的。
//需要特別指出,整個核心只有一個大核心鎖,其實不難理解,核心只有一個,而大核心鎖是保護整個核心的,當然有且只有一個就足夠了。
//還需要特別指出的是,大核心鎖是曆史遺留,核心中用的非常少,一般保持該鎖的時間較長,因此不提倡使用它。
//從2.6.11核心起,大核心鎖可以通過配置核心使其變得可搶佔(自旋鎖是不可搶佔的),這時它實質上是一個互斥鎖,使用訊號量實現。
//大核心鎖的API包括:
//
//void lock_kernel(void);
//
//該函數用於得到大核心鎖。它可以遞迴調用而不會導致死結。
//
//void unlock_kernel(void);
//
//該函數用於釋放大核心鎖。當然必須與lock_kernel配對使用,調用了多少次lock_kernel,就需要調用多少次unlock_kernel。
//大核心鎖的API使用非常簡單,按照以下方式使用就可以了:
//lock_kernel(); //對被保護的共用資源的訪問 … unlock_kernel();
//http://blog.csdn.net/universus/archive/2010/05/25/5623971.aspx
lock_kernel();
//初始化time ticket,時鐘
tick_init();
//函數 tick_init() 很簡單,調用 clockevents_register_notifier 函數向 clockevents_chain 通知鏈註冊元素:
// tick_notifier。這個元素的回呼函數指明了當時鐘事件裝置資訊發生變化(例如新加入一個時鐘事件裝置等等)時,
//應該執行的操作,該回呼函數為 tick_notify
//http://blogold.chinaunix.net/u3/97642/showart_2050200.html
boot_cpu_init();
//初始化頁地址,當然對於arm這裡是個空函數
//http://book.chinaunix.net/special/ebook/PrenticeHall/PrenticeHallPTRTheLinuxKernelPrimer/0131181637/ch08lev1sec5.html
page_address_init();
printk(KERN_NOTICE "%s", linux_banner);
//繫結構相關的核心初始化過程
//http://www.cublog.cn/u3/94690/showart_2238008.html
setup_arch(&command_line);
//初始化記憶體管理
mm_init_owner(&init_mm, &init_task);
//處理啟動命令,這裡就是設定的cmd_line
setup_command_line(command_line);
//這個在定義了SMP的時候有作用,現在這裡為空白函數;對於smp的使用,後面在看。。。
setup_nr_cpu_ids();
//如果沒有定義CONFIG_SMP宏,則這個函數為空白函數。
//如果定義了CONFIG_SMP宏,則這個setup_per_cpu_areas()函數給每個CPU分配記憶體,
//並拷貝.data.percpu段的資料。為系統中的每個CPU的per_cpu變數申請空間。
setup_per_cpu_areas();
//定義在include/asm-x86/smp.h。
//如果是SMP環境,則設定boot CPU的一些資料。在引導過程中使用的CPU稱為boot CPU
smp_prepare_boot_cpu();/* arch-specific boot-cpu hooks */
//設定node 和 zone 資料結構
//記憶體管理的講解:http://blog.chinaunix.net/space.php?uid=361890&do=blog&cuid=2146541
build_all_zonelists(NULL);
//初始化page allocation相關結構
page_alloc_init();
printk(KERN_NOTICE "Kernel command line: %s/n", boot_command_line);
//解析核心參數
//對核心參數的解析:http://hi.baidu.com/yuhuntero/blog/item/654a7411e45ce519b8127ba9.html
parse_early_param();
parse_args("Booting kernel", static_command_line, __start___param,
__stop___param - __start___param,
&unknown_bootoption);
/*
* These use large bootmem allocations and must precede
* kmem_cache_init()
*/
//初始化hash表,以便於從進程的PID獲得對應的進程描述指標,按照實際的實體記憶體初始化pid hash表
//這裡涉及到進程管理http://blog.csdn.net/satanwxd/archive/2010/03/27/5422053.aspx
pidhash_init();
//初始化VFS的兩個重要資料結構dcache和inode的緩衝。
//http://blog.csdn.net/yunsongice/archive/2011/02/01/6171324.aspx
vfs_caches_init_early();
//把編譯期間,kbuild設定的異常表,也就是__start___ex_table和__stop___ex_table之中的所有元素進行排序
sort_main_extable();
//初始化中斷向量表
//http://blog.csdn.net/yunsongice/archive/2011/02/01/6171325.aspx
trap_init();
//memory map初始化
//http://blog.csdn.net/huyugv_830913/archive/2010/09/15/5886970.aspx
mm_init();
/*
* 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.
*/
//核心進程調度器初始化,調度器的初始化的優先順序要高於任何中斷的建立,
//並且初始化進程0,即idle進程,但是並沒有設定idle進程的NEED_RESCHED標誌,
//所以還會繼續完成核心初始化剩下的事情。
//這裡僅僅為進程發送器的執行做準備。
//它所做的具體工作是調用init_bh函數(kernel/softirq.c)把timer,tqueue,immediate三個人物隊列加入下半部分的數組
sched_init();
/*
* Disable preemption - early bootup scheduling is extremely
* fragile until we cpu_idle() for the first time.
*/
//搶佔計數器加1
preempt_disable();
//檢查中斷是否開啟
if (!irqs_disabled()) {
printk(KERN_WARNING "start_kernel(): bug: interrupts were "
"enabled *very* early, fixing it/n");
local_irq_disable();
}
//Read-Copy-Update的初始化
//RCU機制是Linux2.6之後提供的一種資料一致性訪問的機制,
//從RCU(read-copy-update)的名稱上看,我們就能對他的實現機制有一個大概的瞭解,
//在修改資料的時候,首先需要讀取資料,然後產生一個副本,對副本進行修改,
//修改完成之後再將老資料update成新的資料,此所謂RCU。
//http://blog.ednchina.com/tiloog/193361/message.aspx
//http://blogold.chinaunix.net/u1/51562/showart_1341707.html
rcu_init();
//定義在lib/radix-tree.c。
//Linux使用radix樹來管理位於檔案系統緩衝區中的磁碟塊,
//radix樹是trie樹的一種
//http://blog.csdn.net/walkland/archive/2009/03/19/4006121.aspx
radix_tree_init();
/* init some links before init_ISA_irqs() */
//early_irq_init 則對數組中每個成員結構進行初始化,
//例如, 初始每個中斷源的中斷號.其他的函數基本為空白.
early_irq_init();
//初始化IRQ中斷和終端描述符。
//初始化系統中支援的最大可能的中斷描述結構struct irqdesc變數數組irq_desc[NR_IRQS],
//把每個結構變數irq_desc[n]都初始化為預先定義好的壞中斷描述結構變數bad_irq_desc,
//並初始化該中斷的鏈表表頭成員結構變數pend
init_IRQ();
//prio-tree是一棵尋找樹,管理的是什嗎?
//http://blog.csdn.net/dog250/archive/2010/06/28/5700317.aspx
prio_tree_init();
//初始化定時器Timer相關的資料結構
//http://www.ibm.com/developerworks/cn/linux/l-cn-clocks/index.html
init_timers();
//對高精度時鐘進行初始化
hrtimers_init();
//非強制中斷初始化
//http://blogold.chinaunix.net/u1/51562/showart_494363.html
softirq_init();
//初始化時鐘源
timekeeping_init();
//初始化系統時間,
//檢查系統定時器描述結構struct sys_timer全域變數system_timer是否為空白,
//如果為空白將其指向dummy_gettimeoffset()函數。
//http://www.ibm.com/developerworks/cn/linux/l-cn-clocks/index.html
time_init();
//profile只是核心的一個調試效能的工具,
//這個可以通過menuconfig中的Instrumentation Support->profile開啟。
//http://www.linuxdiyf.com/bbs//thread-71446-1-1.html
profile_init();
if (!irqs_disabled())
printk(KERN_CRIT "start_kernel(): bug: interrupts were "
"enabled early/n");
//與開始的early_boot_irqs_off相對應
early_boot_irqs_on();
//與local_irq_disbale相對應,開中斷
local_irq_enable();
/* Interrupts are enabled now so all GFP allocations are safe. */
gfp_allowed_mask = __GFP_BITS_MASK;
//memory cache的初始化
//http://my.chinaunix.net/space.php?uid=7588746&do=blog&id=153184
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.
*/
//初始化控制台以顯示printk的內容,在此之前調用的printk,只是把資料存到緩衝區裡,
//只有在這個函數調用後,才會在控制台列印出內容
//該函數執行後可調用printk()函數將log_buf中符合列印層級要求的系統資訊列印到控制台上。
console_init();
if (panic_later)
panic(panic_later, panic_param);
//如果定義了CONFIG_LOCKDEP宏,那麼就列印鎖依賴資訊,否則什麼也不做
lockdep_info();
/*
* Need to run this when irqs are enabled, because it wants
* to self-test [hard/soft]-irqs on/off lock inversion bugs
* too:
*/
//如果定義CONFIG_DEBUG_LOCKING_API_SELFTESTS宏
//則locking_selftest()是一個空函數,否則執行鎖自測
locking_selftest();
#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./n",
page_to_pfn(virt_to_page((void *)initrd_start)),
min_low_pfn);
initrd_start = 0;
}
#endif
//頁面初始化,可以參考上面的cgroup機制
page_cgroup_init();
//頁面分配debug啟用
enable_debug_pagealloc();
//此處函數為空白
kmemtrace_init();
//memory lead偵測初始化,如何偵測???
kmemleak_init();
//
//Called after the kmem_caches are functional to setup a dedicated
//cache pool, which has the SLAB_DEBUG_OBJECTS flag set. This flag
//prevents that the debug code is called on kmem_cache_free() for the
//debug tracker objects to avoid recursive calls.
//在kmem_caches之後表示建立一個高速緩衝池,建立起SLAB_DEBUG_OBJECTS標誌。???
debug_objects_mem_init();
//idr在linux核心中指的就是整數ID管理機制,
//從本質上來說,這就是一種將整數ID號和特定指標關聯在一起的機制
//idr機制適用在那些需要把某個整數和特定指標關聯在一起的地方。
//http://blogold.chinaunix.net/u3/93255/showart_2524027.html
idr_init_cache();
//是否是對SMP的支援,單核是否需要??這個要分析
setup_per_cpu_pageset();
//NUMA (Non Uniform Memory Access) policy
//具體是什麼不懂
numa_policy_init();
if (late_time_init)
late_time_init();
//初始化調度時鐘
sched_clock_init();
//calibrate_delay()函數可以計算出cpu在一秒鐘內執行了多少次一個極短的迴圈,
//計算出來的值經過處理後得到BogoMIPS 值,
//Bogo是Bogus(偽)的意思,MIPS是millions of instructions per second(每秒百萬指令數)的縮寫。
//這樣我們就知道了其實這個函數是linux核心中一個cpu效能測試函數。
//http://blogold.chinaunix.net/u2/86768/showart_2196664.html
calibrate_delay();
//PID是process id的縮寫
//http://blog.csdn.net/satanwxd/archive/2010/03/27/5422053.aspx
pidmap_init();
//來自mm/rmap.c
//分配一個anon_vma_cachep作為anon_vma的slab緩衝。
//這個技術是PFRA(頁框回收演算法)技術中的組成部分。
//這個技術為定位而生——快速的定位指向同一頁框的所有頁表項。
anon_vma_init();
#ifdef CONFIG_X86
if (efi_enabled)
efi_enter_virtual_mode();
#endif
//建立thread_info緩衝
thread_info_cache_init();
//申請了一個slab來存放credentials??????如何理解?
cred_init();
//根據實體記憶體大小計算允許建立進程的數量
//http://www.jollen.org/blog/2006/11/jollen_linux_3_fork_init.html
fork_init(totalram_pages);
//給進程的各種資源管理結構分配了相應的對象緩衝區
//http://www.shangshuwu.cn/index.php/Linux核心的進程建立
proc_caches_init();
//建立 buffer_head SLAB 緩衝
buffer_init();
//初始化key的management stuff
key_init();
//關於系統安全的初始化,主要是存取控制
//http://blog.csdn.net/nhczp/archive/2008/04/29/2341194.aspx
security_init();
//與debug kernel相關
dbg_late_init();
//調用kmem_cache_create()函數來為VFS建立各種SLAB分配器緩衝
//包括:names_cachep、filp_cachep、dquot_cachep和bh_cachep等四個SLAB分配器緩衝
vfs_caches_init(totalram_pages);
//建立訊號隊列
signals_init();
/* rootfs populating might need page-writeback */
//回寫相關的初始化
//http://blog.csdn.net/yangp01/archive/2010/04/06/5454822.aspx
page_writeback_init();
#ifdef CONFIG_PROC_FS
proc_root_init();
#endif
//它將剩餘的subsys初始化.然後將init_css_set添加進雜湊數組css_set_table[ ]中.
//在上面的代碼中css_set_hash()是css_set_table的雜湊函數.
//它是css_set->subsys為雜湊索引值,到css_set_table[ ]中找到對應項.然後調用hlist_add_head()將init_css_set添加到衝突項中.
//然後,註冊了cgroup檔案系統.這個檔案系統也是我們在使用者空間使用cgroup時必須掛載的.
//最後,在proc的根目錄下建立了一個名為cgroups的檔案.用來從使用者空間觀察cgroup的狀態.
//http://blogold.chinaunix.net/u1/51562/showart_1736813.html
cgroup_init();
//http://blogold.chinaunix.net/u1/51562/showart_1777937.html
cpuset_init();
////進程狀態初始化,實際上就是分配了一個儲存線程狀態的快取
taskstats_init_early();
delayacct_init();
//此處為一空函數
imv_init_complete();
//測試CPU的各種缺陷,記錄檢測到的缺陷,以便於核心的其他部分以後可以使用他們工作。
check_bugs();
//電源相關的初始化
//http://blogold.chinaunix.net/u/548/showart.php?id=377952
acpi_early_init(); /* before LAPIC and SMP init */
//
sfi_init_late();
ftrace_init();
/* Do the rest non-__init‘ed, we‘re now alive */
//建立1號進程,詳細分析之
rest_init();
}
http://blog.csdn.net/skywalkzf/article/details/6415708 rest_init 分析