• 上次介绍了NOVA文件系统,接下来的任务就是怎么开始代码上手NOVA文件系统了。博主具有一定强迫症,开发内核前一定要想配置好可视化Debug方法,不想用printk,或是其他方法。
  • 另外,现有的配置NOVA的方案都是直接改虚拟机的grub来模拟NVM,然后要为虚拟机更换内核,各种操作比较麻烦,可能把原有虚拟机搞崩,基于这一系列问题,本文提供一种用QEMU模拟NVM并且利用VSCODE可视化Debug的方法,希望能够成为某些和博主一样类型的人的福音。
  • 话不多说,芜湖,起飞✈:)

1. 环境配置

  • CentOS 8服务器(虚拟机一样的)
  • VSCode安装Remote-SSH拓展(用于远程连接服务器
  • VSCode安装Native debug拓展(用于Debug)
    在这里插入图片描述

2. QEMU安装

这里我用的是QEMU 5.1.0

[deadpool@localhost linux-nova]$ qemu-system-x86_64 -version
QEMU emulator version 5.1.0
Copyright (c) 2003-2020 Fabrice Bellard and the QEMU Project developers

安装步骤(从源码安装):

# 获取压缩包
wget https://download.qemu.org/qemu-5.1.0.tar.xz
# 解压
tar xvJf qemu-5.1.0.tar.xz
# 切换目录
cd qemu-5.1.0
# 仅配置x86_64的虚拟环境(因为NOVA目前仅支持X86架构)
./configure --disable-kvm --disable-werror --prefix=/usr/local --target-list="x86_64-softmmu" --enable-libpmem
# 编译(用最大核心数编译)
echo $(nproc)
make -j$(nproc)
# 安装至路径/usr/local下
sudo make install

运行下述命令保证安装成功:

qemu-system-x86_64 -version

3. NOVA内核编译

第一步:获取内核源码:

git clone git://github.com/NVSL/linux-nova.git
# 切换至源码目录
cd linux-nova

第二步:配置编译选项

# 配置x86_64默认选项
make defconfig
# 查看内核版本
cat .config | grep Linux/x86
# 如果不是4.18,那可能要切换一下分支,至于为何是4.18,这是因为博主只在4.18上测试成功
git checkout 4.18
# 打开NOVA要求的几个选项
make menuconfig
  • 第一处配置:在Device Drivers选项中
    在这里插入图片描述

  • 第二处配置:在File Systems选项中
    在这里插入图片描述

  • 第三处配置:在Processor type and features
    在这里插入图片描述

  • 第四处配置:在Memory Management options在这里插入图片描述

  • 最后:回到Device Drivers选项,找到DAX: direct access to differentiated memory,进入,做如下勾选:
    在这里插入图片描述

# 接下来配置内核Debug选项,直接用命令即可
# 下述代码-e表示enable,-d表示disable
./scripts/config -e DEBUG_INFO -e GDB_SCRIPTS -e CONFIG_DEBUG_SECTION_MISMATCH -e CONFIG_FRAME_POINTER -d CONFIG_RANDOMIZE_BASE

第三步:编译内核
编译内核并不困难,虽然我们通常被吓到。直接make就好了。

make -j$(nproc)

编译完成后,会看到如下提示:

Kernel: arch/x86/boot/bzImage is ready

这告诉我们内核镜像已经准备好了。

内核编译速度视机器不同而不同。由于博主的服务器配置有点小好,所以用-j32编几分钟就编好了。如果是差一点的机器,可能要编上好几个小时,这时候摸鱼就好了🤭

4. Initrd选择与QEMU启动内核

如何用QEMU启动可以Debug的内核呢?最简单的方法如下:

qemu-system-x86_64 \
  -kernel arch/x86_64/boot/bzImage \
  -nographic \
  -smp 1 \
  -append "console=ttyS0 nokaslr" \
  -s -S

这里简单解释一下各参数的作用:

  • -kernel:指定内核bzImage
  • -nographic:由于服务器没有配置可视化界面,因此去掉GUI;
  • -smp:核心数量;
  • -append:系统启动参数。console=ttyS0 nokaslr指定用ttyS0设备(该设备是串口输出)作为输出,nokaslr说明取消内存地址随机化,避免调试的时候出现乱七八糟的情况;
  • -s:默认GDB调试端口为localhost: 1234
  • -S:停止在系统入口;

遗憾的是,光这样还不行,需要指定initrdinitrd全称init ram disk,即初始化的RAM文件系统initrd必须和内核版本相适应。具体的制作博主并没有参透,等之后参透了会再发博客🤭,这里用了一个取巧的办法:

题外话:已经知道怎么做了,嘿嘿 👉 传送门

无意中发现/boot目录下有很多initramfs

[deadpool@localhost linux-nova]$ ls /boot/
config-4.18.0-240.el8.x86_64                             System.map
config-4.18.0-305.10.2.el8_4.x86_64                      System.map-4.18.0-240.el8.x86_64
config-4.18.0-305.12.1.el8_4.x86_64                      System.map-4.18.0-305.10.2.el8_4.x86_64
efi                                                      System.map-4.18.0-305.12.1.el8_4.x86_64
grub2                                                    System.map-5.1.0
initramfs-0-rescue-badf97bbe70d402e99024dbf5317e538.img  vmlinuz
initramfs-4.18.0-240.el8.x86_64.img                      vmlinuz-0-rescue-badf97bbe70d402e99024dbf5317e538
initramfs-4.18.0-240.el8.x86_64kdump.img                 vmlinuz-4.18.0-240.el8.x86_64
initramfs-4.18.0-305.10.2.el8_4.x86_64.img               vmlinuz-4.18.0-305.10.2.el8_4.x86_64
initramfs-4.18.0-305.12.1.el8_4.x86_64.img               vmlinuz-4.18.0-305.12.1.el8_4.x86_64
initramfs-5.1.0.img                                      vmlinuz-5.1.0
loader

而且刚好NOVA文件系统支持4.18版本的内核,因此直接拷贝一个过来用即可,我这里拷贝的是initramfs-4.18.0-305.12.1.el8_4.x86_64.img

qemu-system-x86_64 \
  -kernel arch/x86_64/boot/bzImage \
  -nographic \
  -smp 1 \
  -append "console=ttyS0 nokaslr" \
  -initrd /boot/initramfs-4.18.0-305.12.1.el8_4.x86_64.img \
  -s -S

这个镜像已上传,在这里获取

好了,现在系统可以正常启动了:在一个终端中运行上述命令,ctrl + sheit + ~呼出新的终端,运行gdb vmlinux,运行即可:在这里插入图片描述
这里要注意,gdb起来以后,本来需要输入额外的命令来让gdb attach到QEMU进程上。这一步我通过修改./scripts/gdb/vmlinux-gdb.py文件做到了自动执行,如下图所示:
在这里插入图片描述
即,在try里面加入:

gdb.execute("target remote :1234", to_string=True)

这样一来,就能够让gdb attach到QEMU上了,系统成功启动,截图如下:
在这里插入图片描述
但现在有个问题,NVM设备在哪里?
在这里插入图片描述

5. NVM设备模拟

5.1 官方方案

官方给出了一种利用NVM模拟方案:

sudo qemu-system-x86_64 
  -m 4G,slots=4,maxmem=32G \
  -smp 4 \
  -machine pc,nvdimm=on \
  -object memory-backend-file,id=mem1,share,mem-path=/virtual-machines/qemu/f27nvdimm0,size=4G \
  -device nvdimm,memdev=mem1,id=nv1,label-size=2M \
  -object memory-backend-file,id=mem2,share,mem-path=/virtual-machines/qemu/f27nvdimm1,size=4G \
  -device nvdimm,memdev=mem2,id=nv2,label-size=2M \
  -kernel arch/x86_64/boot/bzImage \
  -nographic \
  -append "console=ttyS0 nokaslr" \
  -initrd /boot/initramfs-4.18.0-305.12.1.el8_4.x86_64.img \
  -s -S

但是这种模拟方式模拟的是裸板。利用NOVA挂载的时候会报错:设备不支持DAX,解决方法应该是使用impctl等NVM工具来进行配置,这里博主没有研究过,先不谈了。

5.2 个人方案

最终解决方案是在-append参数中加入memmap,即仍然使用与修改GRUB类似的方式来启动QEMU,完整命令如下:

qemu-system-x86_64 \
  -kernel arch/x86_64/boot/bzImage \
  -nographic \
  -smp 1 \
  -append "console=ttyS0 nokaslr memmap=1G!1G" \
  -initrd /boot/initramfs-4.18.0-305.12.1.el8_4.x86_64.img \
  -s -S \
  -m 8G

关于memmap设置方式及其含义,可以参考这里。与第4节方法一样启动QEMU,截图如下:
在这里插入图片描述
至此,我们成功模拟出了一块NVM设备:pmem0

6. 利用VSCode可视化调试

在源码树的.vscode中,添加launch.json文件,内容如下(确保有Native Debug拓展):

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Native Debugger for Linux",
            "type": "gdb",
            "request": "attach",
            "executable": "${workspaceRoot}/vmlinux",
            "gdbpath": "gdb",
            "target": "127.0.0.1:1234",
            "cwd": "${workspaceRoot}"
        }
    ]
}

在终端运行第5.2节介绍命令:

qemu-system-x86_64 \
  -kernel arch/x86_64/boot/bzImage \
  -nographic \
  -smp 1 \
  -append "console=ttyS0 nokaslr memmap=1G!1G" \
  -initrd /boot/initramfs-4.18.0-305.12.1.el8_4.x86_64.img \
  -s -S

之后按下F5,系统就启动了。接下来,在nova_fill_super的位置打个断点,可以看到,效果杠杠滴。
在这里插入图片描述
ok,从现在开始,可以起飞🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫🛫

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐