一、實驗步驟:
1:運行menuos:
a)cd LinuxKernel/
b)qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img
啟動后啟動了MenuOS。
2:使用gdb調試跟蹤menuos內核啟動和運行過程;
a)qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S
-S:freeze CPU at startup
-s:shorthand for -gdb tcp::1234 如果不想使用1234端口則可以好似用 -gdb tcp:xx 來取代-s選項
在另外一個窗口調試程序打開gdb;
然后按c運行到剛才的斷點,如下圖:
然后使用list,查看start_kernel的代碼
如果想跟蹤那里,結合代碼,設置斷點繼續跟蹤;
二、從start_kernel到init進程啟動過程的詳細分析
1.Linux內核啟動時首先調用start_Kernel函數,該函數相當于應用程序中的main()函數,在start_kernel函數中會調用大量的init函數來對內核環境進行初始化;包括CPU初始化、內存管理初始化、進程管理初始化、文件系統初始化、中斷、同步互斥等。例如:
asmlinkage __visible void __init start_kernel(void)
{
.......
/*init_task即手工創建的PCB,0號進程就是最終的idle進程*/
thread_info_cache_init();//初始化thread info
cred_init();
fork_init(totalram_pages);//初始化fork
proc_caches_init();//初始化proc的catch
buffer_init();
key_init();
security_init();
dbg_late_init();//文件系統初始化
vfs_caches_init(totalram_pages);
signals_init();
/* rootfs populating might need page-writeback */
page_writeback_init();
proc_root_init();
cgroup_init();
cpuset_init();
taskstats_init_early();
delayacct_init();
check_bugs();
sfi_init_late();
if (efi_enabled(EFI_RUNTIME_SERVICES)) {
efi_late_init();
efi_free_boot_services();
}
ftrace_init();
/*以上就是各種初始化*/
/* Do the rest non-__init'ed, we're now alive */
rest_init();
}
2.從上面代碼我們看到最后一步就是:調用rest_init()函數來啟動第一個用戶進程,該進程被稱為1號進程,代碼及分析如下所示:(這個函數可以直接斷點到這里,然后按c運行到這里即可)
static noinline void __init_refok rest_init(void)
{
int pid;
rcu_scheduler_starting();
/*
* We need to spawn init first so that it obtains pid 1, however
* the init task will end up wanting to create kthreads, which, if
* we schedule it before we create kthreadd, will OOPS.
*/
kernel_thread(kernel_init, NULL, CLONE_FS);//啟動1號進程,也稱為init進程,是第一個用戶進程
numa_default_policy();
pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
rcu_read_lock();
kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
rcu_read_unlock();
complete(&kthreadd_done);
/*
* The boot idle thread must execute schedule()
* at least once to get things moving:
*/
init_idle_bootup_task(current);
schedule_preempt_disabled();
/* Call into cpu_idle with preempt disabled */
cpu_startup_entry(CPUHP_ONLINE); //由1號進程完成剩下的初始化工作
}我們可以看到這個進程,有一個while(1)在無限的執行下去;