bintasong 原创作品转载请注明出处《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
0 笔记
1.1 x86计算机启动过程
(1)CS:EIP=FFFF:0000H启动BIOS程序
(2)BIOS例行程序检测完硬件并完成相应的初始化之后就会寻找可引导介质.把引导程序加载到指定内存区域
(3)引导程序BootLoader开始负责操作系统初始化,然后起动操作系统。
(4)内核启动过程包括start_kernel之前和之后,之前全部是做初始化的汇编指令,之后开始C代码的操作系统初始化,最后执行第一个用户态进程init。
1 实验截图
(1)b start_kernel,b rest_kernel设置断点,运行c:
(2)执行到rest_kernel,(gdb) s 进入rest_kernel关注执行过程:
(3)最终启动
2 进程执行分析
(1) 首先,进程执行start_kernel()函数,该函数是内核的入口,从此处开始利用c语言内核初始化。
(2) 在start_kernel()尾部执行rest_init(),这是内核初始化的尾声。
(3) 进入rest_init(),创建一个内核线程
kernel_thread(kernel_init, NULL, CLONE_FS);
通过查看kernel_init函数,我们发现以下代码:
if (!try_to_run_init_process("/sbin/init") ||
!try_to_run_init_process("/etc/init") ||
!try_to_run_init_process("/bin/init") ||
!try_to_run_init_process("/bin/sh"))
return 0;
尝试运行磁盘上的init可执行文件
(4)进入 cpu_startup_entry
(5)进入 cpu_idle_loop,执行一个while(1)循环。
static void cpu_idle_loop(void)
{
while (1) {
/*
* If the arch has a polling bit, we maintain an invariant:
*
* Our polling bit is clear if we're not scheduled (i.e. if
* rq->curr != rq->idle). This means that, if rq->idle has
* the polling bit set, then setting need_resched is
* guaranteed to cause the cpu to reschedule.
*/
__current_set_polling();
tick_nohz_idle_enter();
while (!need_resched()) {
check_pgt_cache();
rmb();
if (cpu_is_offline(smp_processor_id()))
arch_cpu_idle_dead();
local_irq_disable();
arch_cpu_idle_enter();
/*
* In poll mode we reenable interrupts and spin.
*
* Also if we detected in the wakeup from idle
* path that the tick broadcast device expired
* for us, we don't want to go deep idle as we
* know that the IPI is going to arrive right
* away
*/
if (cpu_idle_force_poll || tick_check_broadcast_expired())
cpu_idle_poll();
else
cpuidle_idle_call();
arch_cpu_idle_exit();
}
/*
* Since we fell out of the loop above, we know
* TIF_NEED_RESCHED must be set, propagate it into
* PREEMPT_NEED_RESCHED.
*
* This is required because for polling idle loops we will
* not have had an IPI to fold the state for us.
*/
preempt_set_need_resched();
tick_nohz_idle_exit();
__current_clr_polling();
/*
* We promise to call sched_ttwu_pending and reschedule
* if need_resched is set while polling is set. That
* means that clearing polling needs to be visible
* before doing these things.
*/
smp_mb__after_atomic();
sched_ttwu_pending();
schedule_preempt_disabled();
}
}
3 分析
在linux内核启动过程中,初始化代码执行到start_kernel(),执行各种系统初始化,在start_kernel尾部执行rest_init,在rest_init中通过执行根文件系统上的init可执行文件创建了第一个pid=1的进程,这时内核初始化已经完成,0号进程蜕变成一个idel进程,该进程是一个while(1)循环,并在循环中检测是否有调度产生,当有进程队列新进程产生切换至新进程。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。