您的位置:首页 > 运维架构 > Linux

分析Linux内核的启动过程

2017-05-22 17:55 323 查看
第一章 环境

Ubuntu 14.10

Linux Kernel 3.18.6

第二章 代码及调试过程

环境搭建与内核准备:

cd ~/LinuxKernel/
wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.18.6.tar.xz xz -d linux-3.18.6.tar.xz
tar -xvf linux-3.18.6.tar
cd linux-3.18.6
make i386_defconfig
make

cd ~/LinuxKernel/
mkdir rootfs
git clone  https://github.com/mengning/menu.git cd menu
gcc -o init linktable.c menu.c test.c -m32 -static –lpthread
cd ../rootfs
cp ../menu/init ./
find . | cpio -o -Hnewc |gzip -9 > ../rootfs.img

cd ~/LinuxKernel/
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img
又一次编译内核:

make menuconfig
kernel hacking—>
compile-time checks and compile options
[*] compile the kernel with debug info
開始调试:

qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S
同一时候另开一个窗体。执行GDB:

gdb
(gdb)file linux-3.18.6/vmlinux
(gdb)target remote:1234
(gdb)break start_kernel
(gdb)list


这一次代码就不贴出来了,在init/mian.c下,主要是代码太长。

http://codelab.shiyanlou.com/xref/linux-3.18.6/init/main.c

单击对应的链接能够找到引用的变量位置。我下载了几个。

这里打算分析:

cpu_startup_entry

page_address_init()

rest_init()

page_alloc_init()

trap_init()

tick_init()

profile_init()

key_init()

security_init()

buffer_init()

init_task 0号进程

run_init_process(const char *init_filename) 1号进程

0号进程init_task的结构:

#define INIT_TASK(tsk)	\
{									\
.state		= 0,						\
.stack		= &init_thread_info,				\
.usage		= ATOMIC_INIT(2),				\
.flags		= PF_KTHREAD,					\
.prio		= MAX_PRIO-20,					\
.static_prio	= MAX_PRIO-20,					\
.normal_prio	= MAX_PRIO-20,					\
.policy		= SCHED_NORMAL,					\
.cpus_allowed	= CPU_MASK_ALL,					\
.nr_cpus_allowed= NR_CPUS,					\
.mm		= NULL,						\
.active_mm	= &init_mm,					\
.se		= {						\
.group_node 	= LIST_HEAD_INIT(tsk.se.group_node),	\
},								\
.rt		= {						\
.run_list	= LIST_HEAD_INIT(tsk.rt.run_list),	\
.time_slice	= RR_TIMESLICE,				\
},								\
.tasks		= LIST_HEAD_INIT(tsk.tasks),			\
INIT_PUSHABLE_TASKS(tsk)					\
INIT_CGROUP_SCHED(tsk)						\
.ptraced	= LIST_HEAD_INIT(tsk.ptraced),			\
.ptrace_entry	= LIST_HEAD_INIT(tsk.ptrace_entry),		\
.real_parent	= &tsk,						\
.parent		= &tsk,						\
.children	= LIST_HEAD_INIT(tsk.children),			\
.sibling	= LIST_HEAD_INIT(tsk.sibling),			\
.group_leader	= &tsk,						\
RCU_POINTER_INITIALIZER(real_cred, &init_cred),			\
RCU_POINTER_INITIALIZER(cred, &init_cred),			\
.comm		= INIT_TASK_COMM,				\
.thread		= INIT_THREAD,					\
.fs		= &init_fs,					\
.files		= &init_files,					\
.signal		= &init_signals,				\
.sighand	= &init_sighand,				\
.nsproxy	= &init_nsproxy,				\
.pending	= {						\
.list = LIST_HEAD_INIT(tsk.pending.list),		\
.signal = {{0}}},					\
.blocked	= {{0}},					\
.alloc_lock	= __SPIN_LOCK_UNLOCKED(tsk.alloc_lock),		\
.journal_info	= NULL,						\
.cpu_timers	= INIT_CPU_TIMERS(tsk.cpu_timers),		\
.pi_lock	= __RAW_SPIN_LOCK_UNLOCKED(tsk.pi_lock),	\
.timer_slack_ns = 50000, /* 50 usec default slack */		\
.pids = {							\
[PIDTYPE_PID]  = INIT_PID_LINK(PIDTYPE_PID),		\
[PIDTYPE_PGID] = INIT_PID_LINK(PIDTYPE_PGID),		\
[PIDTYPE_SID]  = INIT_PID_LINK(PIDTYPE_SID),		\
},								\
.thread_group	= LIST_HEAD_INIT(tsk.thread_group),		\
.thread_node	= LIST_HEAD_INIT(init_signals.thread_head),	\
INIT_IDS							\
INIT_PERF_EVENTS(tsk)						\
INIT_TRACE_IRQFLAGS						\
INIT_LOCKDEP							\
INIT_FTRACE_GRAPH						\
INIT_TRACE_RECURSION						\
INIT_TASK_RCU_PREEMPT(tsk)					\
INIT_TASK_RCU_TASKS(tsk)					\
INIT_CPUSET_SEQ(tsk)						\
INIT_RT_MUTEXES(tsk)						\
INIT_VTIME(tsk)							\
}


第三章 调试

设置断点:一共13个。

命令为:

(gdb)break <function name>
接着输入c进行调试。

流程例如以下:



来几张有代表性的调试图片:

start_kernel:



page_address_init:



buffer_init:



security_init:



cpu_startup_entry:





run_init_process:



第四章 总结

通过这个方式我们知道了。Linux内核通过调用那些函数来启动,看起来在启动的时候仅仅有些跳动的字符,但是在内部是非常忙碌的。希望以后能了解到每个函数的详细作用。只是,这就非常困难的了。

set_task_stack_end_magic确立一个init_task。这个便是后来的0号进程,也就是idle。

通过參考资料:http://blog.chinaunix.net/uid-27767798-id-3577069.html

通过检測时钟中断来提醒idle进程来复制自己的进程信息,来创建一个进程。

就好像之前的myKernel一样。

然后idle进程就会检測,假设有新的任务便会中断执行。生成并释放系统资源让进程使用。当进程结束,系统便将资源收回返回给idle进程。

当执行到run_init_process时。1号进程便開始执行。

附录

卢晅 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: