作业3:构造一个简单的Linux系统MenuOS 20135115臧文君

构造一个简单的Linux系统MenuOS

注:作者:臧文君,原创作品转载请注明出处,《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

一、Linux内核源代码介绍

1、根目录

arch/x86目录下的代码是我们重点关注的,arch中包括支持不同CPU的源代码。

init目录下包含内核启动相关的代码,如main.c(start_kernel函数相当于普通C程序的main函数,是Linux内核初始化的起点)。

ipc:进程间通信

kernel:Linux内核的核心代码

关注readme文件

二、构造一个简单的Linux系统MenuOS

<步骤指导>

1、在实验楼环境下:

cd LinuxKernel/

qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img

即可启动内核,完成后进入menu程序,支持三个命令help、version和quit。

2、使用自己的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  # 如果被墙,可以使用附件menu.zip 

cd menu

gcc -o init linktable.c menu.c test.c -m32 -static –lpthread(init是第一个用户态进程,是1号进程,采用的是静态编译的方式)

cd ../rootfs

cp ../menu/init ./

find . | cpio -o -Hnewc |gzip -9 > ../rootfs.img(img镜像文件)

# 启动MenuOS系统

cd ~/LinuxKernel/

qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img

3、重新配置编译Linux使之携带调试信息

(1)在原来配置的基础上,make menuconfig选中如下选项重新配置Linux,使之携带调试信息

kernel hacking—>

[*] compile the kernel with debug info

(2)make重新编译(时间较长)

4、使用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界面中target remote之前加载符号表    file home/shiyanlou/LinuxKernel/vmlinux

(gdb)target remote:1234 # 建立gdb和gdbserver之间的连接,按c 让qemu上的Linux继续运行

(gdb)break start_kernel # 断点的设置可以在target remote之前,也可以在之后

三、跟踪调试Linux内核的启动过程

1、之前内核启动被冻结,断点设置完成后,打C回车可以恢复启动。

命令:(gdb)list查看断点前后的代码

 

在rest_init()前设置断点:break rest_init(),再按C运行,list查看代码。

 

2、简单分析一下start_kernel

在init目录下的main.c中

 

全局变量init_task,即手工创建的PCB,0号进程即最终的idle进程。

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

 

trap_init();初始化中断向量

例:set_system_trap_gate(SYSCALL VECTOR,&system_call)系统陷阱门(系统调用)

mm_init();内存管理模块

sched_init();系统调度模块

start_kernel中的最后一句:rest_init();在start_kernel从内核一启动就一直存在,是0号进程。

0号进程创建了1号进程kernel_init。

当系统没有进程需要执行时就调度到idle进程。

 

道生一,一生二,二生三,三生万物。

实验报告:

1、cd home/YL/menu/rootfs,启动linux内核:qemu-system-x86_64 -kernel /boot/vmlinuz-4.3.0-kali1-amd64 -initrd ../rootfs.img

注:find . | cpio -o -Hnewc | gzip -9 > ../rootfs.img将当前目录下的所有文件打包压缩生成img镜像文件

 

 

2、qemu-system-x86_64 -kernel /boot/vmlinuz-4.3.0-kali1-amd64 -initrd ../rootfs.img -s -S,启动linux内核,停在起始部位,设置断点进行调试。

 

3、重新开一个终端窗口,输入gdb,可以使用help命令查看可选择的命令。

 

4、在gdb界面中target remote之前加载符号表:先切换到usr/src/linux-source-4.4路径下,然后输入命令file vmlinux。再建立gdb和gdbserver之间的连接:target remote:1234。

 

5、在start_kernel前设置断点:break start_kernel,按c 让qemu上的Linux继续运行

 

总结:

      这次实验是构造一个简单的linux系统MenuOS,使用老师已经配置好的虚拟机,做起来比较方便,但因为linux内核的版本不同以及配置的原因,所以在命令的使用上与网课中介绍的有一些差别,主要是路径的不同,在理解了各个命令中参数的含义后,命令使用起来会比较容易,实验也能顺利的进行。

      在课上的巩固讲解中,我了解到linux内核启动的三要素是:kernel,initrd和root所在分区。对于内核启动,最重要的命令就是:qemu-system-x86_64 -kernel /boot/vmlinuz-4.3.0-kali1-amd64 -initrd ../rootfs.img。在之后的gdb调试过程中,要注意路径!

      start_kernel是内核启动的起点,存在于init目录下main.c文件中。init_kernel即手工创建的PCB,0号进程即最终的idle.不论分析内核的哪一部分都会涉及start_kernel,模块初始化时需要调用start_kernel。在start_kernel中最后一句rest_init是start_kernel从内核启动时就一直存在的0号进程,0号进程创建了1号进程和其他的内核服务线程。

原文地址:https://www.cnblogs.com/CatherineZang/p/5270066.html