搭建Linux kernel调试环境-busybox构建最小根文件系统

       调试Linux kernel时经常使用printk将信息打印到内核消息ring buffer中,为了方便查看内核相关Log,并减少不必要的干扰,有必要构建一个小型根文件系统,在该系统内进行模块加载、Log查看、状态监控等kernel调试。busybox是一个功能完备的Linux命令行工具集,又可作为init进程配置文件系统,在嵌入式系统中应用广泛。本文记录了使用busybox构建简易Linux根文件系统的过程,并在该系统内抓取了kernel Log。

一.  搭建环境:

      操作系统(编译使用):CentOS 7.6

      busybox版本:1.31.0

      kernel版本:4.18.9

      Qemu版本:3.0.1(4.1.0要求DSL2及以上版本,CentOS7.6由于DSL版本低会导致Qemu4.1.0编译后没有界面)

      调试平台:x86_64

二. 编译kernel

     kernel编译前必须开启initramfs支持,设置如下 :

     make menuconfig启动图形配置界面,进入General setup,选中如下画线项。本文使用外置initramfs,没有设置Initramfs source file(s)。

     kernel再开启文件系统extension支持:进入File systems内,选择Ext2 extended attributes开启ext2增强属性。

     若编译64bit内核,则支持加载32bit busybox,编译32bit内核则只能加载32bit busybox。此处编译了64bit内核。

     编译完成后在/arch/x86/boot/下生成了bzImage文件,后续会引导该文件。

三. 编译Busybox

     进入busybox源文件目录,命令行输入make menuconfig开启图形配置,设置为静态编译。

Settings->Build Options->Build static binary

由于把busybox作为init进程,若不使用静态编译,则启动busybox会动态加载so文件,so文件依赖关系多,制作initramfs文件必须逐一提取so文件,非常繁琐且体积大。init作为kernel启动的第一个进程,应力求减少复杂的so文件加载过程,尽快开启更多子进程以并行执行初始化。

       配置编译64bit busybox。进入Settings->Additional CFLAGS,设置-m64。

     退出图形配置界面。检查CentOS是否存在glibc-static库,若不存在则yum install安装。

make编译busybox,在源文件目录下生成busybox可执行文件,使用命令行:file busybox 检查该文件为ELF-64,即64bit程序。

make install 安装busybox,在busybox源文件目录下生成_install目录,内部有如下目录:

这四个文件/文件夹后续在initramfs中会使用。

四. 配置initramfs

     1.  在/home下新建文件夹ramdisk,将第三步生成的_install文件夹内容拷贝到ramdisk下,同时新建目录和文件:

mkdir dev var sys mnt etc proc lib home tmp
mkdir var/log
mkdir lib/modules
touch var/log/dmesg
touch var/log/messages
touch var/log/kern.log
ln -s bin/busybox init 

chmod 755 bin/*
chmod 755 sbin/*
chmod 777 init
chmod 666 var/log/*

生成的ramdisk目录内容如下:

2. 为了简便直接借用busybox的example,将busybox源目录example/bootfloopy/etc目录下的内容拷贝到ramdisk/etc下,新建syslog.conf空文件。

修改inittab文件如下:

::sysinit:/etc/init.d/rcS
::askfirst:-/bin/sh
::restart:/sbin/init 
::ctrlaltdel:/sbin/reboot 
::respawn:/sbin/klogd -n
::respawn:/sbin/syslogd -n
::shutdown:/bin/umount -a -r 
::shutdown:/sbin/swapoff -a
::shutdown:/bin/killall klogd
::shutdown:/bin/killall syslogd

      此处在init启动时开启了klogd和syslogd进程,这两个进程用于抓取kernel Log到指定文件中。klogd和syslogd的相互关系和kernel Log的数据流动方向见下图,数据传递的详细过程见内核源码kernel/printk.c文件。

修改init.d/rcS文件内容如下,其中添加一些打印信息记录init启动状态,收集kernel启动信息到dmesg文件中。

#! /bin/sh

mount -o remount,rw /
mount -a
clear
echo "Start Busybox Linux..."
echo "Now remount"
dmesg > /var/log/dmesg

修改syslog.conf内容如下,分发不同等级的消息到不同的Log文件内。

user.* /var/log/messages
kern.* /var/log/kern.log
authpriv.* /var/log/messages

3. 在ramdisk/dev目录下新建设备文件

cd dev
mknod console c 5 1
mknod null c 1 3

4. 添加shutdown命令。这里直接借用busybox的example,将example/shutdown-1.0/script/shutdown脚本拷贝到ramdiak/bin下,并添加执行权限 chmod +x bin/shutdown 。

5. 封装ramdisk文件夹为initramfs-busybox.cpio.gz

在ramdisk目录下执行命令:

find . -print0 | cpio --block-size=8 --null -ov --format=newc | gzip -9 > ../initramfs-busybox.cpio.gz

ramdisk父目录下生成initramfs-busybox.cpio.gz。

五. 加载initramfs并调试

   将initramfs-busybox.cpio.gz拷贝到某一位置,启动qemu运行Linux kernel,命令如下(提前安装Qemu,此处不再赘述):

qemu-system-x86_64 -m 10240 -kernel bzImage -initrd initramfs-busybox.cpio.gz

 kernel运行进入busybox,并开启syslogd和klogd进程。

此时kernel相关log保存在var/log目录下:

       在该界面中可以使用mount挂载硬盘将Log拷出来,可以用proc调试kernel状态。系统重启后所有状态清空。至此最小根文件系统构建完成。

六.  提取SATA控制器驱动

      第五步制作的initramfs文件未包含驱动模块,在系统启动时使用了kernel内置驱动,这些驱动中未包含SATA控制器驱动,因此无法挂载SATA硬盘。

      内核make menuconfig提供了SATA控制器驱动以模块形式加载,需开启如下选项:

        其中Intel ESB, ICH, PIIX3, PIIX4 PATA/SATA support为Intel芯片组SATA控制器驱动,需根据硬件选择。为了减小initramfs文件的大小,设置所有模块为xz压缩模式,勾选Enable loadable module support ,选择Compression algorithm 为XZ。

         最后save保存,编译内核模块make modules。编译完成后,将模块安装到自定义位置

make modules_install INSTALL_MOD_PATH=./modules

        模块安装后在modules文件夹下有kernel版本对应的文件夹,提取该文件夹下的五个模块:

1.  modules/4.18.9/kernel/drivers/scsi/sd_mod.ko.xz

2.  modules/4.18.9/kernel/drivers/ata/ahci.ko.xz   ata_piix.ko.xz   libahci.ko.xz    libata.ko.xz

这些模块与menuconfig下配置的选项一一对应,查看KConfig和Makefile可以找到其对应关系。

        使用modinfo查看模块依赖,并在ramdisk内补全依赖模块。

        对于initramfs其他驱动的集成,参考CentOS7的initramfs文件构成,其中的模块依赖完整,可保证基本功能正常。若要查找某个设备对应的驱动名称,在CentOS下,首先找到该设备在sys中的对象,再使用udevadm得到该设备及所在总线控制器的驱动模块名称。

         解压CentOS的initramfs rootfs文件的命令是:

cd initramfsdir
/usr/lib/dracut/skipcpio ../initramfs-$(uname -r)| zcat | cpio -id

七. 集成SATA控制器驱动

         在/usr/lib/modules下创建4.18.9文件夹,将上一步提取的模块放入对应路径下。修改ramdisk文件夹下lib为文件链接:

ln -s usr/lib  lib
ln -s usr/lib64 lib64

         此时可使用depmod生成模块依赖cache文件,以便为后续udev自动加载模块作准备。由于不打算自动加载模块,此处不做该操作。完成后的ramdisk文件夹结构如下:

           最后打包生成initramfs文件。

八. 测试硬盘挂载

        使用qemu-img生成一个vdi磁盘,并在启动时加载该硬盘:

qemu-img create -f vdi -o preallocation=metadata -o static=on ./diskf.vdi 10G

qemu-system-x86_64 -m 10240 -kernel bzImage -initrd initramfs-busybox.cpio.gz diskf.vdi

       启动kernel,进入命令行,cd 进入模块路径,按顺序依次加载模块 libata--->libahci--->ahci--->ata_piix--->sd_mod      

进入/dev下,存在磁盘文件sda,格式化并挂载sda,后续便可以对该磁盘正常操作。

硬盘加载后,就可以保存Log,进行更多操作了。

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值