操作系统内核分析 实验一 Linux系统启动过程

需要的基本工具及文件:

  • VMware Workstation 15 player
  • ubuntu-18.04.3-desktop-amd64.iso镜像文件
  • Linux源码
  • busybox源码

一、准备实验环境

(一)、下载ubuntu镜像

  1. 进入 ubuntu 官网下载页,如图1。
  2. 点击 Ubuntu Desktop,进入图2。
  3. 再点击 Ubuntu 18.04.3 LTS 版本右侧的 Download ,开始下载。
  4. 得到 ubuntu-18.04.3-desktop-amd64.iso 镜像文件。

(二)、安装Ubuntu虚拟机

  1. 进入VMware官网,按下图下载 VMware Workstation 15 Player ,安装完成后继续,此处安装过程省略。
  2. 打开 VMware Workstation 15 Player ,点击 创建新虚拟机 ,之后按图5操作,之后耐心等待安装完成。
  3. 安装结束,自动进入登录界面,可点击之前简易安装创建的用户,输入密码登录。到此安装Ubuntu虚拟机完成。



二、配置、编译linux内核以及busybox

因为刚开始学Linux,本文产生文件统一放在桌面,便于理解。大家可以按照自己需要,自行修改教程中的命令代码,选择存放位置。 若自行修改了文件路径,后面使用该文件时,也请注意修改文件路径

(一)安装开发套件及工具

  1. 在桌面右键单击,选择 Open Terminal菜单项,进入终端界面。
  2. 在命令提示符后面,依次输入执行以下命令,过程中需要输入账户密码。
sudo apt update                                 #检查更新

sudo apt install build-essential                #基本开发套件
sudo apt install gcc-multilib
sudo apt install git                            #分布式版本控制系统
  1. 安装结束后,可通过gcc --version检验gcc安装是否成功,成功将显示gcc版本信息。
    同样,也可通过git --version检验git安装是否成功,成功将显示git版本信息。
  2. git配置(仅使用git克隆远程仓库,可跳过此步):
git config --global  "nickname"             #其中nickname,改成你想要的用户名
git config --global user.email "XXX@mail.com"        #XXX@mail.com,改成你的个人邮箱
  1. 获取Linux源码和Busybox源码到桌面,时间因网速而异,耐心等待。执行完,会在桌面生成一个名为linux的文件夹和一个名为busybox的文件夹。
cd ~/Desktop                                                #改变路径,用于后面克隆代码到桌面
	git clone https://mirrors.tuna.tsinghua.edu.cn/git/linux.git #linux内核源码(国外源较慢,这里从清华大学镜像服务器获取内核源码)
	git clone git://git.busybox.net/busybox                   #Busybox 是一个集成了大多数常用 Linux 命令 和工具的软件。
  1. 安装编译内核所需的软件包
sudo apt install flex
	sudo apt install bison
	sudo apt install libncurses5-dev
	sudo apt install pkg-config
	sudo apt install libglade2-dev
	sudo apt install libssl-dev
	sudo apt install libelf-dev

(二)配置、编译linux内核

  1. 首先进入linux文件夹
cd ~/Desktop/linux
  1. 清除以前的编译结果及配置信息(可跳过)
    若之前有配置、编译过内核可执行该操作清除编译、配置结果,对于新克隆的源码可跳过此步
make mrproper
  1. 配置linux内核
make defconfig                    #配置内核(按默认选项配置)
make menuconfig                   #进入图形化的内核配置界面,自定义配置
进入图形化的内核配置界面后,接着按下面操作
 	1)按【↓】箭头键,找到最下面的  Kernel hacking,按【enter】键进入该配置项
 	2)按【↓】箭头键,找到 Compile-time checks and compiler options ,按【enter】键进入该配置项
 	3)按【↑】【↓】箭头键调整选项,找到 Compile the kernel with debug info,按【空格键】选中
 	4)此时,出现一些Compile the kernel with debug info的子配置项,找到Provide GDB scripts for kernel debugging,也按【空格键】选中
 	5)连按两下【ESC】键,退出该配置项,再连按两下【ESC】键,退回配置主页。
 	6)找到并回车进入 Processor type and features 选项,再在接近底部的Build a relocatable kernel 项下,按【空格键】去掉配置项Randomize the address of the kernel image (KASLR)
 	7)多次连按【ESC】,退出配置,此时提示是否希望保存新的配置,回车选择Yes。回到终端,继续执行本文后面命令。

  1. 编译linux内核
make                             #编译内核,持续时间比较久,耐心等待

(三)配置、编译busybox

  1. 配置 Busybox,生成配置文件
cd ~/Desktop/busybox                       #进入之前克隆的busybox源码目录
make defconfig                             #配置 Busybox,生成配置文件(按默认选项配置)
make menuconfig                            #进入图形化的配置界面
进入图形化的配置界面后,接着按下面操作
 1) 进入Setting  --直接按【enter】进入配置组
 2) 按【↓】箭头键,找到构建选项  build options
 3) 按【↓】箭头键,找到构建选项下的 build static binary (no shared libs),按【空格键】,选中
 4) 按下【esc】退出配置组
 5) 再按下【esc】,提示保存修改,按【enter】键选择 yes 确认保存
 6) 配置完成,回到终端继续执行本文后面命令
  1. 编译busybox
make install -j2                       #编译busybox 
#-j 参数指定了可并行执行的作业数,通常设为计算机 CPU 数目的两倍以提高编译速度。
# 持续时间一丢丢久,耐心等待,直到显示
# --------------------------------------------------
# You will probably need to make your busybox binary
# setuid root to ensure all configured applets will
# work properly.
# --------------------------------------------------

三、用 Busybox 制作根文件系统

  1. 进入桌面文件夹
cd ~/Desktop
  1. 创建 100M 磁盘镜像 rootfs.img
dd if=/dev/zero of=rootfs.img bs=1M count=100
  1. 在磁盘镜像中创建 ext4 根文件系统
mkfs.ext4  rootfs.img
  1. 挂载刚刚创建的根文件系统
mkdir rootfs
sudo mount -o loop rootfs.img  rootfs                    #需要输入密码
  1. 创建文件夹
cd rootfs
sudo rm -rf lost+found
sudo mkdir -pv {bin,sbin,etc/init.d,proc,sys,usr/{bin,sbin},tmp,dev}
  1. 在根文件系统上安装 busybox
sudo cp -drv ~/Desktop/busybox/_install/* . 
sudo chmod u+s bin/busybox                            #给bin文件夹下busybox文件设置setuid标志
													  #即 使文件在执行阶段具有文件所有者的权限
  1. 创建系统配置文件 /etc/inittab (若权限不足,则先执行sudo bash)
sudo cat > etc/inittab << EOF
出现大于号【>】形状的提示符后,复制下面五行代码,粘贴进去(代码前面无空格)
 	
 	::sysinit:/etc/init.d/rcS
 	::respawn:-/bin/sh
 	::restart:/sbin/init
 	::shutdown:/bin/umount -a -r
 	EOF
  1. 创建系统设置脚本 /etc/init.d/rcS
sudo cat > etc/init.d/rcS << EOF
出现大于号【>】形状的提示符后,复制下面十行代码,粘贴进去(代码前面无空格)
 	
 	#!/bin/sh
 	echo "INIT SCRIPT"
 	mount -t proc proc /proc
 	mount -t sysfs sysfs /sys
 	mount -t debugfs debugfs /sys/kernel/debug
 	mount -t tmpfs tmpfs /tmp
 	mdev -s
 	mount -n -o remount,rw /
 	echo -e "\nBoot took $(cut -d' ' -f1 /proc/uptime) seconds\n"
 	EOF
  1. 赋予rcS文件执行权限
sudo chmod +x etc/init.d/rcS
  1. 卸载根文件系统
cd ../
sudo umount rootfs

若卸载时提示target is busy,则执行fuser -v rootfs 查看占用rootfs的进程。
查看没什么特别大的问题,则执行fuser -k rootfs可以直接结束使用rootfs文件的进程。
然后可能需要打开终端,cd ~/Desktop进入桌面后,再次卸载根文件系统sudo umount rootfs


四、运行及调试内核

  1. 安装 qemu 虚拟机软件
sudo apt install qemu
  1. 在 home 目录下创建 .gdbinit 文件
cd /home
cat > ~/.gdbinit << EOF
出现大于号【>】形状的提示符后,复制下面2行代码,粘贴进去(代码前面无空格)
 	add-auto-load-safe-path path/to/linux
 	EOF
  1. qemu 创建并运行虚拟机
sudo qemu-system-x86_64 -kernel ~/Desktop/linux/arch/x86_64/boot/bzImage -hda ~/Desktop/rootfs.img -append  "console=ttyS0 root=/dev/sda" -nographic -s -S
#执行该命令之后,因为加了-S参数,会挂起虚拟机,所以没有执行迹象请不要惊慌,继续后面步骤

【部分参数说明】:
-s 参数:为虚拟机启动一个 gdbserver ,等待 gdb 客户端连接。默认 tcp 端口 1234 。
-S 参数:挂起虚拟机,直到 gdb 客户端连接并 给出继续执行的指令。

  1. 用 gdb 调试内核
    前面终端中虚拟机处于挂起状态,我们要调试内核,必须要另外再开一个终端,通过tcp端口1234执行gdb调试,所以以下代码在另一个终端中进行
#新开一个终端,执行以下命令
cd ~/Desktop/linux                                      #进入linux内核源码根目录
gdb vmlinux                                             #以内核可执行文件作为参数运行 gdb
target remote :1234                                     #连接至 gdbserver

break start_kernel                                      #使用break设置函数断点
break rest_init
break kernel_init
break run_init_process

info breakpoints                                        #查看所有设置的断点

continue                                                #继续程序执行(遇到断点会停止运行)
  1. 添加断点成功后,即可开始调试
    调试过程中,可以激活源码浏览窗口,查看执行位置附件的源码。
    快捷键 【Ctrl + x, a】(重复这一操作可以反复隐藏/显示源码浏览窗口。)
当内核程序运行至断点处时将暂停运行,在终端B的gdb调试环境中综合运用下列调试指令来跟踪调试内核程序 
 •	step(单步执行,当执行函数调用时会跟踪进入函数内部)
 •	next(单步执行,执行函数调用时不会跟踪进入函数内部)
 •	finish(从一个函数内部返回到上一层调用它的地方)
 •	continue(运行暂停的程序直到下一个断点处)
 •	backtrace(查看当前正在调试的程序的函数调用栈)
  1. 调试内核,了解linux启动过程
  2. 正常调试截图
  3. 正常退出
    1)先结束 qemu ,按【ctrl+a,x】,提示 QEMU: Terminated即为qemu退出成功
    2)再退出 gdb ,在 gdb 所在终端,输入quit回车即可。