linux内核分析实验楼实验8,《Linux内核分析》之构造一个简单的Linux系统MenuOS 实验总结...

环境搭建与配置过程

个人Linux系统环境搭建MenuOS的过程 [toggle hide="yes" title="Linux系统环境搭建MenuOS的过程" color=""] 1、Linux系统环境搭建MenuOS的过程

# 下载内核源代码编译内核

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 # 一般要编译很长时间,少则20分钟多则数小时

# 制作根文件系统

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

# 启动MenuOS系统

cd ~/LinuxKernel/

qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img 2、重新配置编译Linux使之携带调试信息 在原来配置的基础上,make menuconfig选中如下选项重新配置Linux,使之携带调试信息

kernel hacking—>

[*] compile the kernel with debug info make重新编译(时间较长) 3、使用gdb跟踪调试内核

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)

# -s shorthand for -gdb 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之前,也可以在之后 [/toggle]

在实验楼中的过程 [toggle hide="yes" title="实验楼中实验过程" color=""] 使用

实验楼的虚拟机打开shell

cd LinuxKernel/

qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img 使用gdb跟踪调试内核

qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -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之前,也可以在之后 部分步骤如下图所示 [caption id="" align="aligncenter" width="308"]

dc9cd31df66f34963417db6c5bce528e.png 没有-S和-s时[/caption] [caption id="" align="aligncenter" width="298"]

6714a13a413a6c167945182236e3b226.png 有-s和-S时[/caption] [caption id="" align="aligncenter" width="286"]

a9eb5a691298ec0d85f8ebda4e09a22e.png gdb[/caption] [caption id="" align="aligncenter" width="284"]

99b416f9370c7434a5fd97339967eaae.png break start_kernel[/caption]   [caption id="" align="aligncenter" width="277"]

a45feaa0a3aefdefb4ae6928c51953c6.png 通过list查看break start_kernel后start_kernel前后文代码[/caption]   [/toggle]

相关代码分析

start_kernel函数

所在位置:

xref: /

linux-3.18.6/

init/

main.c 不管分析内核的哪一部分都会涉及到start_kernel

asmlinkage __visible void __init start_kernel(void)

{

.......

/*init_task即手工创建的PCB,0号进程就是最终的idle进程*/

set_task_stack_end_magic(&init_task);

........

/*初始化中断向量*/

trap_init();

/*内存管理模块初始化*/

mm_init();

/*调度模块初始化*/

sched_init();

....

/*其他初始化*/

rest_init()

}   trap_init();初始化一些中断向量,

主要分析函数所在地址:

xref: /

linux-3.18.6/

arch/

x86/

kernel/

traps.c rest_init();中包含内核启动过程

rest_init()函数 从系统内核一启动,rest_init()会一直存在,是

0号进程,并且创建了

1号进程,并创建了一些其他的服务进程*/

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.

*/

/*初始化了第一个用户态的进程1号进程*/

kernel_thread(kernel_init, NULL, CLONE_FS);

numa_default_policy();

/*创建内核线程管理系统资源

*kthreadd 为内核线程

*/

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);

}

kernel_init 原语句:kernel_thread(kernel_init, NULL, CLONE_FS); 所在位置(非语句):

xref: /

linux-3.18.6/

init/

main.c 其中主要分析的代码所在的代码段

if (ramdisk_execute_command) {

ret = run_init_process(ramdisk_execute_command);

if (!ret)

return 0;

pr_err("Failed to execute %s (error %d)n",

ramdisk_execute_command, ret);

} run_init_process  init_process为一号进程,第一个用户态进程

cpu_startup_entry 原语句:cpu_startup_entry(CPUHP_ONLINE); 所在位置(非语句):

xref: /

linux-3.18.6/

kernel/

sched/

idle.c 其中主要分析的代码

cpu_idle_loop(); 所在位置(非语句):

xref: /

linux-3.18.6/

kernel/

sched/

idle.c 主要作用: cpu_idle_loop是一个

while(

1)循环,当系统没有进程需要执行时就调度到idle进程 其实是0号进程实现部分。 0号进程一直存在,并创建一号进程及其他服务的内核线程。

总结 Linux内核的启动,通过start_kernel()进行各种初始化工作,最终执行到rest_init()来初始化0号进程,同时0号进程创建1号用户态的进程以及其他服务的一些内核线程。然后操作系统就运行起来了。 windCoder原创作品转载请注明出处

参考资料 《

Linux内核分析》MOOC课程

http://mooc.study.163.com/course/USTC-1000029000

本文同步分享在 博客“蜜汁炒酸奶”(other)。

如有侵权,请联系 support@oschina.cn 删除。

本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值