构造一个简单的Linux系统MenuOS

李雪琦 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

计算机三个法宝:

  • 1、存储程序计算机
  • 2、函数调用堆栈
  • 3、中断

操作系统两把宝剑:

  • 1、中断上下文的切换:保存现场和恢复现场
  • 2、进程上下文的切换

一、阅读Linux内核代码

本周我们要学习如何阅读Linux内核源代码,首先打开Lstest Stable Kernel:linux-3.18.6

arch/目录在Linux内核中占有相当庞大的代码量,因为Linux支持很多CPU,这个arch/x86目录下的代码是我们重要关注的代码。

根目录中比较关键的目录:

  • Documentation/文档
  • fs/文件系统
  • init/内核启动相关的代码基本都在init目录下,里面的main.c是整个Linux内核启动的起点。它的起点是start_kernel

start_kernel函数相当于普通C程序的main函数。

  • ipc/进程间通信
  • kernel/Linux内核的核心代码在kernel目录中
  • lib/公用的库文件
  • mm/memmory management内存管理
  • net/与网络相关的代码
  • security/与安全相关的代码
  • scripts/脚本

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

使用实验楼的虚拟机打开shell。linux-3.18.6.tar就是内核源代码,rootfs里面有用menu编译好的init可执行文件,rootfs.img是它生成的。输入help会有以下三条命令。

使用gdb跟踪调试内核

输入以下命令

qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -S -s
  • S表示:在CPU初始化之前,冻结CPU
  • s表示在:1234端口上创建一个tcp接口

水平分割,再打开一个shell窗口,输入gdb

输入(gdb)file linux-3.18.6/vmlinux

targe remote之前加载符号表

Reading后,连接到刚启动的被冻结的linux系统,设置断点,把内核启动的起点start_kernel设为断点,在init/main.c文件中,第501行

输入c,回车,系统从冻结状态开始执行,启动。

输入list,可以看见start_kernel代码上下的这段代码

再设一个断点rest_init,按c继续执行

系统已经执行到rest_init

输入list,看rest_init前后的代码

在start_kernel尾部被调用











三、简单分析start_kernel

1. init/main.c -> stat_kernel

asmlinkage void __init start_kernel(void)该函数是Linux内核的入口。

start_kernel()是内核的汇编与C语言的交接点,在该函数以前,内核的代码都是用汇编写的,完成一些最基本的初始化与环境设置工作。

在start_kernel()中Linux将完成整个系统的内核初始化。内核初始化的最后一步就是启动init进程,这个所有进程的祖先。

不管分析内核那一部分都会涉及到start_kernel,因为几乎所有模块在初始化时都会调用它。

2. 一些init函数

(1)全局变量 init_task

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

(2)初始化一些中断向量 trap_init()

中断向量表的初始化函数,设置了很多中断门(Interrupt Gate)

set_intr_gate:设置中断门

(3)内存管理模块初始化 mm_init()

(4)调度模块初始化 sched_init()

函数内做了很关键的一步初始化——对0号进程,即idle进程进行初始化。

(5)其它模块初始化 rest_init()

kernel_thread``(kernel_init,NULL,CLONE_FS)中的kernel_init包含一个run_init_process,创建了一号进程,即第一个用户态进程。之后创建了kthread,一个内核线程来管理系统的资源。

各部分启动完毕后,调用static void cpu_idle_loop(void),当系统没有进程需要执行时就调度到idle进程中的cpu_idle_loop,其中while(1)无限循环,即rest_init的中0号进程会一直存在。

四、总结

qemu -kernel (文件名) -initrd (rootfs.img)
  • qemu相当于打开一个虚拟机

  • kernel启动一个内核,位置由其后的文件名指定。如果在当前目录下,可以直接输入文件名,如果不是,则需要输入该内核的全路径。

  • initrd指令是挂了一个ramdisk虚拟硬盘,是内核的重要补充,rootfs.img就是这个虚拟硬盘,内有分区,然后启动的其实是其中的init文件,这个文件是由之前的menuOS编译而成,gcc -o命名为init。

所以就是要启动一个内核,挂一个硬盘,然后再运行一个init即1号进程。

也就是说,init中main.c中有一个start_kernel函数

start_kernel函数的尾部调用了一个rest_init

有一个全局变量init_task,即手工创建的PCB,0号进程,即最终的idle进程。0号进程一直存在,系统没有进程需要执行时调度到0号进程。

rest_init()中有kernel_thread(kernel_init,NULL,CLONE_FS)

kernel_init中有run_init_processrun_init_process创建了一号进程。

最新文章

  1. Xcode 调试技巧
  2. jquery中bind()绑定多个事件
  3. 走进AngularJs(三)自定义指令-----(上)
  4. java source not found
  5. 网站开发中很实用的 HTML5 & jQuery 插件
  6. C# DateTime显示时间格式的使用
  7. Python JavaScript概述
  8. python_day5--->递归函数,二分法查找
  9. tensorflow+入门笔记︱基本张量tensor理解与tensorflow运行结构
  10. 5.1.3.jvm java虚拟机系统参数查看
  11. 5.2、Android Studio截图
  12. java集合框架--List、Set、Map
  13. openstack虚拟机内核崩溃问题解决
  14. WPF 播放声音 百度文字转声音
  15. RabbitMQ系列目录
  16. IS-IS笔记
  17. Docker网络解决方案-Flannel(转)
  18. python+Django+apache的配置
  19. Linux守护进程编写方法及原理
  20. 《Linux内核设计与实现》第1、2章读书笔记

热门文章

  1. linux 同步 rsync的使用——远程服务器同步配置
  2. PHP精确到毫秒秒杀倒计时实例
  3. 百度地图之自动提示--autoComplete
  4. django中model字段与属性
  5. 搭建RTSP服务器时nginx的nginx.conf文件配置
  6. EasyUI 效果还不错的数据处理等待效果
  7. JavaScript学习笔记(四)——DOM
  8. java学习笔记-01.对象入门
  9. 云主机启动提示Booting from Hard Disk GRUB
  10. echarts.js使用心得--demo