秦鼎濤 《Linux內核分析》MOOC課程http://mooc.study.163.com/course/USTC-1000029000
一、實驗目的及要求:
-
使用gdb跟蹤調試內核從start_kernel到init進程啟動
-
詳細分析從start_kernel到init進程啟動的過程并結合實驗截圖撰寫一篇署名博客,并在博客文章中注明“真實姓名(與最后申請證書的姓名務必一致) + 原創作品轉載請注明出處 + 《Linux內核分析》MOOC課程http://mooc.study.163.com/course/USTC-1000029000?”,博客內容的具體要求如下:
-
題目自擬,內容圍繞Linux內核的啟動過程,即從start_kernel到init進程啟動;
-
博客中需要使用實驗截圖
-
博客內容中需要仔細分析start_kernel函數的執行過程
-
總結部分需要闡明自己對“Linux系統啟動過程”的理解,尤其是idle進程、1號進程是怎么來的。
-
-
3)請提交博客文章URL到網易云課堂MOOC平臺Linux內核分析MOOC課程,編輯成一個鏈接可以直接點擊打開。?
二、實驗步驟(含實驗樓截圖):
1、登陸實驗樓虛擬機
打開shell終端,執行以下命令:
cd LinuxKernel/
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage-initrd rootfs.img
2、使用gdb跟蹤調試內核
執行以下命令:
cd LinuxKernel/
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage-initrd rootfs.img -s -S
關于-s和-S選項的說明:
-S freeze CPU at startup (use ’c’ to start execution) 在系統啟動的時候凍結CPU,使用c鍵繼續執行后續操作
-s shorthand for -gdb tcp::1234 打開遠程調試端口,默認使用tcp協議1234端口,若不想使用1234端口,則可以使用-gdb tcp:xxxx來取代-s選項
?
打開另外一個shell終端,執行以下命令
gdb
(gdb)file linux-3.18.6/vmlinux # 在gdb界面中targe remote之前加載符號表
(gdb)target remote:1234 # 建立gdb和gdbserver之間的連接,按c 讓qemu上的Linux繼續運行
(gdb)break start_kernel # 斷點的設置可以在target remote之前,也可以在之后
(不知道為什么沒有找到文件目錄。。)
?
三、start_kernel函數的執行過程分析:
asmlinkage void __init start_kernel(void)
?char * command_line;
?extern struct kernel_param __start___param[], __stop___param[];
/*
?* Interrupts are still disabled. Do necessary setups, then
?* enable them
?*/
?lock_kernel();
?page_address_init();
?printk(linux_banner);
?setup_arch(&command_line);
?setup_per_cpu_areas();
? * Mark the boot cpu "online" so that it can call console drivers in
? * printk() and can access its per-cpu storage.
? */
?smp_prepare_boot_cpu();
? * 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();
?build_all_zonelists();
?page_alloc_init();
?printk("Kernel command line: %s\n", saved_command_line);
?parse_early_param();
?parse_args("Booting kernel", command_line, __start___param,
???? __stop___param - __start___param,
???? &unknown_bootoption);
?sort_main_extable();
?trap_init();
?rcu_init();
?init_IRQ();
?pidhash_init();
?init_timers();
?softirq_init();
?time_init();
? * 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();
?if (panic_later)
??panic(panic_later, panic_param);
?profile_init();
?local_irq_enable();
#ifdef CONFIG_BLK_DEV_INITRD
?if (initrd_start && !initrd_below_start_ok &&
???initrd_start < min_low_pfn << PAGE_SHIFT) {
??printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "
????? "disabling it.\n",initrd_start,min_low_pfn << PAGE_SHIFT);
??initrd_start = 0;
?}
#endif
?vfs_caches_init_early();
?mem_init();
?kmem_cache_init();
?numa_policy_init();
?if (late_time_init)
??late_time_init();
?calibrate_delay();
?pidmap_init();
?pgtable_cache_init();
?prio_tree_init();
?anon_vma_init();
#ifdef CONFIG_X86
?if (efi_enabled)
??efi_enter_virtual_mode();
#endif
?fork_init(num_physpages);
?proc_caches_init();
?buffer_init();
?unnamed_dev_init();
?security_init();
?vfs_caches_init(num_physpages);
?radix_tree_init();
?signals_init();
?/* rootfs populating might need page-writeback */
?page_writeback_init();
#ifdef CONFIG_PROC_FS
?proc_root_init();
#endif
?check_bugs();
?rest_init();
}
?
四、實驗總結:
當計算機電源啟動,BIOS代碼被調用執行,然后開始調用執行Linux內核初始化代碼,在平臺相關的匯編代碼
執行完畢后會跳轉到start_kernel()函數,開始真正的內核初始化,其中init_task創建了0號進程,即最終的idle進程,
隨后rest_init()函數創建了init進程,即1號進程,以及kthreadd進程,即2號進程,系統開始正式對外工作了。
?