bintasong 原创做品转载请注明出处《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000linux
0 笔记
1.1 x86计算机启动过程
(1)CS:EIP=FFFF:0000H启动BIOS程序
(2)BIOS例行程序检测完硬件并完成相应的初始化以后就会寻找可引导介质.把引导程序加载到指定内存区域
(3)引导程序BootLoader开始负责操做系统初始化,而后起动操做系统。
(4)内核启动过程包括start_kernel以前和以后,以前所有是作初始化的汇编指令,以后开始C代码的操做系统初始化,最后执行第一个用户态进程init。promise
1 实验截图
(1)b start_kernel,b rest_kernel设置断点,运行c:ide
(2)执行到rest_kernel,(gdb) s 进入rest_kernel关注执行过程:函数
(3)最终启动oop
2 进程执行分析
(1) 首先,进程执行start_kernel()函数,该函数是内核的入口,今后处开始利用c语言内核初始化。
(2) 在start_kernel()尾部执行rest_init(),这是内核初始化的尾声。
(3) 进入rest_init(),建立一个内核线程ui
kernel_thread(kernel_init, NULL, CLONE_FS);atom
经过查看kernel_init函数,咱们发现如下代码:spa
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)循环,并在循环中检测是否有调度产生,当有进程队列新进程产生切换至新进程。线程