20189229 张子松 第四周作业

本次写博客之前,先看了看其他已经交了的同学的博客,顿时觉得自己对本章内容理解还不到位,于是又回去重新整理了一遍,将本章内容汇总如下:

MenuOS的构造

基于Linux内核源代码构造一个简单的操作系统MenuOS。

Linux内核源代码简介

计算机的“3大法宝”

- 存储程序计算机
- 函数调用堆栈
- 中断

操作系统有“两把宝剑”

- 中断上下文:保存现场和恢复现场
- 进程上下文

Linux内核源码的目录结构

Linux内核源码的目录结构如下图所示:

关键目录简介

  • arch:与体系结构相关的子目录列表,可以使Linux内核支持不同的CPU和体系结构。
    • x86:在下载源代码研究时,只需留下x86目录中的内容,避免同一个函数存在多个目录中。
  • block:存放块设备管理的代码。
  • crypto:存放常见的加密算法的C语言代码。
  • Documentation:存放一些文档。
  • drivers:驱动目录。
  • firmware:固件。
  • fs:文件系统。
  • include:头文件目录。
  • 存放Linux内核启动时的初始化代码。
    • main.c:源文件是整个Linux内核启动的起点,其中的start_kernel函数是源文件的起点。
  • ipc:IPC为进程间通信。
  • kernel:存放Linux核心代码。
  • lib:公用的库文件目录,但与c语言下的库函数不同,内核编程中不能用c语言标准库函数,所以此lib目录下库函数就是用来替代那些标准库函数的。
  • mm:存放内存管理代码。
  • net:存放与网络相关代码,如TCP/IP协议栈等。

构造一个简单的Linux内核

在构建MenuOS系统时,我选择使用自己的linux系统来构建。

下载内核源代码

建立一个LinuxKernel文件夹,键入以下指令:
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运行内核源代码

!问题!

此处make时会出现找不到compiler-gcc6.h和compiler-gcc7.h文件的错误,查找资料即可发现,compiler-gcc6与compiler-gcc7内容基本相同,所以即可以下载下compiler-gcc6之后复制重命名为compiler-gcc7,再将其放入include/linux目录下即可。

制作根文件系统镜像

返回上级目录,键入如下命令:
mkdir rootfs创建目录用于存放文件系统
git clone https://github.com/mengning/menu.git从GitHub上克隆menu
cd menu
gcc -pthread -o init linktable.c menu.c test.c -m32 -static
cd ../rootfs
cp ../menu/init ./将init复制到rootfs下,因为系统启动时默认先启动init
find . | cpio -o -Hnewc | gzip -9 > ../rootfs.img把当前rootfs下的所有文件打包成一个镜像文件
运行结果如图:

init是第一个用户态进程,是1号进程。把init复制到rootfs目录下边,使用cpio的方式把当前rootfs下的所有文件打包成一个镜像文件,这时一个简单的根文件系统的镜像就制作好了。

重新配置Linux内核,使之携带调试信息

键入如下命令:
make menuconfig
kernel hacking
-> Compile-time checks and compiler options
[*]compile the kernel with debug info
make

!问题!

make menuconfig时找不到curses.h文件,通过键入命令sudo apt-get install libncurses5-dev即可解决。

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

使用gdb跟踪调试内核,需要在内核启动时加-S -s两个参数。
-S使CPU初始化之前冻结起来。
-s在1234端口上创建一个gdb-server,用gdb把带有符号表的内核镜像加载进来,连接gdb-server,设置断点跟踪内核。
启动gdb,将内核加载进来并与1234建立连接,在gdb中键入如下命令:
file linux-3.18.6/vmlinux在gdb界面中target remote之前加载符号表,建立gdb和gdb-server之间的连接,按c``让qemu继续运行。 target remote:1234`用1234这个端口进行连接。
运行结果如下图:

设置断点,分析start_kernel()

在start_kernel()处设置断点,如图。main.c中没有main函数,start_kernel()相当于C语言中的main函数,每次内核从start_kernel()中开始执行,查看start_kernel()处上下代码,会发现start_kernel()函数几乎涉及内核中所有模块包括:trap_init()-中断向量初始化、mm_init()-内存管理的初始化、sched_init-调度模块的初始化等等。

init_task()

init为0号进程,使用宏INIT_TAST对其进行初始化。

rest_tast()

在rest_tast()处设置断点,查看其代码,如图:

调用kernel_thread()创建1号进程。对比init_task()和kernel_thread()函数,kernel_thread()时fork出的一个新进程来执行kernel_init()函数,而init_task时使用宏进行初始化的。调用kernel_thread执行kthreadd,创建2号进程,kthreadd函数的任务是管理和调度其他内核线程kernel_thread。

posted @ 2018-11-04 16:40  张子松20189229  阅读(198)  评论(1编辑  收藏  举报