LINUX内核分析第三周学习总结——构造一个简单的Linux系统MenuOS
LINUX内核分析第三周学习总结——构造一个简单的Linux系统MenuOS
标签(空格分隔): 20135321余佳源
余佳源(原创作品转载请注明出处)
《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
一、知识点总结
计算机三个法宝
存储程序计算机
函数调用堆栈
中断
操作系统两把宝剑
中断上下文的切换
进程上下文的切换
Linux内核源代码简介分析
链接戳这--->Linux内核源代码
概要分析:
·arch/目录保存支持多种CPU类型的源代码,包括:Documentation、drivers、firewall、fs(文件系统)、include
·init目录:含有main.c,内核启动相关的代码基本都在init目录下
·start_kernal()函数为启动函数,初始化内核的起点。
·ipc目录:进程间的通信
·kernel目录:有Linux内核的核心代码。
·pid.c、kthread.c
lib目录:公用库文件
mm目录:内存管理代码
net目录:与网络相关代码
scripts目录:与脚本相关
security目录:与安全相关
sound目录:与声音相关
tools目录:与工具相关
README文件:
介绍了什么是Linux,Linux能够在哪些硬件上运行,如何安装内核源代码等
二、构造一个简单的Linux系统MenuOS
实验环境:
VMware 虚拟机 Linux 系统 Ubuntu kylin 14.02
准备:下载好Linux-3.18.6.tar,通过
xz -d linux-3.18.6.tar.xz
以及tar -xvf linux-3.18.6.tar
命令解开压缩。
实验步骤:
1.cd linux-3.18.6
进入到具体操作的文件夹
2.make i386_defconfig
进行编译
3.使用make menuconfig进行内核配置,在图中项打上*,具体选项如下
kernel hacking—>
[*] compile the kernel with debug info
4.制作根文件系统
在LinuxKernel目录下创建文件夹rootfs,通过git clone https://github.com/mengning/menu.git
下载menu压缩包,解压缩后进入
5.在menu文件夹里进行可执行文件的编译
gcc -o init linktable.c menu.c test.c -m32 -static –lpthread
6.提取出根文件系统rootfs.img
cp ../menu/init ./ find . | cpio -o -Hnewc |gzip -9 > ../rootfs.img
7.启动根文件系统并准备使用GDB调试,由于是本地的虚拟机,所以和指导书上的路径有不同,而且启动指令改为
qemu-system-x86_64 -kernel /home/brotherlittlefish/LinuxKernel/linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S
-S freeze CPU at startup (use ’c’ to start execution)//在启动的时候冻结CPU,可在GDB调试中按'c'执行
-s shorthand for -gdb tcp::1234 //设定一个端口,若不想使用1234端口,则可以使用-gdb tcp:xxxx来取代-s选项
此时这个Ubuntu虚拟机中的虚拟机qemu处于冻结状态
8.使用另一个终端启动gdb,打开可执行文件vmlinux,在gdb界面中targe remote之前加载符号表
一句话:从vmlinux中读取符号表,完成
9.进行GDB调试
输入
——> target remote:1234 # 建立gdb和gdbserver之间的连接,按c 让qemu上的Linux继续运行
——>break start_kernel # 断点的设置可以在target remote之前,也可以在之后
——>按下c启动程序解除冻结
——>按下list,可以看见start_kernel的具体情况
——>break rest_init # 断点设置在rest_init这个函数,如同start_kernel的步骤
10.不设置断点,让根文件系统MENUOS继续运行直到完成开机
PS:输入help可见到该MENUOS有什么具体的功能指令
三、建立系统过程的总结分析
1.关于start_kernel
在init目录下main.c里找到start_kernel函数
可见有一个全局变量init_task,即手工创建的PCB,0号进程即最终的idle进程。0号进程创建了1号进程和其他线程,也就是说不管分析内核的哪一部分都会涉及到start_kernel。
2.三个相关的init
trap_init();初始化一些中断向量
mm_init() 内存管理模块
sched_init() 调度模块
其中rest_init()中有kernel_thread(kernel_init,NULL,CLONE_FS),它是0号进程,创建了1号进程kernel_init()
而kernel_thread()中有kernel_init(),kernel_init()包含了run_init_process,
kernel_init 是linux系统的1号进程,第一个用户态进程,默认根目录下的init程序。
kernel_thread()还创建了kthreadd,一个内核线程来管理系统的资源。
启动完了之后进入了一个cpu_idle,cpu_idle_loop,就是一个while(0)的无限循环,即idle进程,0号进程,一直存在
当系统没有进程需要执行时就调度到idle进程。
3.小结
rest_init就是start_kernel内核启动时一直存在,即为0号进程。0号进程创建了1号进程kernel_init以及其他的服务线程。“道生一(start_kernel....cpu_idle)、一生二(kernel_init和kthreadd)、二生三(即前面0、1和2三个进程)、三生万物(1号进程是所有用户态进程的祖先,2号进程是所有内核线程的祖先)”,内核就启动了。