ubuntu20.04上linux内核开发环境搭建(qemu+gdb+vscode)

  • Post author:
  • Post category:linux




1. 环境准备



1.1 安装基础软件

apt-get install vim

apt-get install vim-scripts

apt-get install vim-gtk

apt-get install fcitx (中文输入法需要)

apt-get install fcitx-libs (中文输入法需要)

apt-get install kolourpaint4(图片编辑软件)

apt-get install rar (压缩、解压文件)

apt-get install unrar

apt-get install wine (模拟win系统环境)

apt-get install hexedit (16进制编辑器)

apt-get install net-tools(网络相关工具)

apt-get install wireshark (可选,抓包软件)



1.2 安装开发软件

apt-get install libncurses5-dev

apt-get install libelf-dev

apt-get install libssl-dev

apt-get install bison

apt-get install git

apt-get install gcc-arm-linux-gnueabi

apt-get install build-essential

apt-get install ninja-build

apt-get install libpixman-1-dev

apt-get install flex(编译用到的词法分析器)



1.3 安装qemu

1)安装qemu

方法一:版本可能较老,但安装速度快

apt-get install qemu-system-x86 (安装x86架构qemu执行程序)

apt install qemu-system-arm (安装arm架构qemu执行程序)

方法二:安装新版本,编译时间长(编译后,生成所有架构的qemu执行程序)

wget https://download.qemu.org/qemu-6.1.0-rc4.tar.xz

tar xvjf qemu-6.1.0-rc4.tar.xz

cd qemu-6.1.0-rc4

./configure

make

2)安装qume工具

apt install qemu-utils



2. 制作rootfs



2.1 buildroot制作rootfs

root@linux:~#wget https://buildroot.org/downloads/buildroot-2020.02.8.tar.gz

root@linux:~#tar zxvf  buildroot-2020.02.8.tar.gz && cd buildroot-2020.02.8

root@linux:~#export ARCH=x86_64

root@linux:~#export FORCE_UNSAFE_CONFIGURE=1

root@linux:~#make menuconfig
Toolchain  --->
    # 编译一些package会用到,比如f2fstools
    [*] Enable WCHAR support
 
System configuration  --->
     # 系统启动后,密码为空,回车登录shell
     [*] Enable root login with password
          ( )    Root password
      # 设置eth0接口为DHCP,如果不设置,qemu启动kernel镜像后,需要手动配置网络
     (eth0) Network interface to configure through DHCP
 
Target packages  --->
    Filesystem and flash utilities  --->
        # 格式化f2fs用到
        [*] f2fs-tools
 
Filesystem images  ---> 
     [ ] ext2/3/4 root filesystem
     # 设置rootfs的文件系统类型
     [*] f2fs root filesystem
root@linux:~#make

编译时间较长,等编译完成后,在output/images目录中生成rootfs.f2fs文件。将该文件拷贝到内核源码目录即可,如下:

root@linux:/home/gsf/linux-5.10.3# ls| grep f2fs
 
rootfs.f2fs


注意点:

1)修改buildroot-2020.02.8/package目录下的package,重新编译前,需要删除output/build/目录中对应的package,否则编译出来的rootfs.f2fs不会包含改动。



2.2 busybox制作rootfs


  • 编译_install目录


    root@linux:/home/gsf/source-code/busybox-1.33.0# export ARCH=arm

    root@linux:/home/gsf/source-code/busybox-1.33.0# export CROSS_COMPILE=arm-linux-guneabi-

    root@linux:/home/gsf/source-code/busybox-1.33.0# make menuconfig

Settings –> Build Options –> [*] Build static binary (no shared libs)。若没有编译成静态库,需要将宿主机/bin、/sbin目录中的动态库文件拷贝到_install目录中。为了简化,编译成静态库即可。

root@linux:/home/gsf/source-code/busybox-1.33.0# make install

编译完成后,会在当前目录中生成一个_install目录。将其拷贝到linux源码根目录。


  • 制作rootfs用到的文件
  1. 将busybox的提供的example中的etc目录拷贝到_install中,,并稍作修改。

    root@linux:/home/gsf/debug/kernel/linux-5.10.3# cp …/busybox-1.33.0/examples/bootfloppy/etc ./_install/ -R

修改1:./_install/etc/inittab

 tty2::askfirst:-/bin/sh   --------->   ::askfirst:-/bin/sh

修改2:./_install/etc/fstab 增加下面3行

sysfs /sys sysfs defaults 0 0

tmpfs /dev tmpfs defaults 0 0

tmpfs /tmp tmpfs defaults 0 0

修改3:./_install/etc/ini.d增加2行,注意顺序,改成下面的样子

#! /bin/sh

mkdir /proc /sys /tmp

/bin/mount -a

mdev -s

  1. 在_install目录中创建基本目录

    root@linux:/home/gsf/debug/kernel/linux-5.10.3/_install# mkdir dev mnt

  2. 在dev目录创建设备节点:

     mknod console c 5 1
     mknod null c 1 1
    



3. kernel编译及运行



3.1 编译内核

内核源码:linux-5.10.3

root@linux:/home/gsf/linux-5.10.3# export ARCH=“x86_64”

root@linux:/home/gsf/linux-5.10.3# make x86_64_defconfig

root@linux:/home/gsf/linux-5.10.3# make menuconfig

Processor type and features  --->

      [ ]   Randomize the address of the kernel image (KASLR)  不要选

Drevice Drivers  --->

      NVME Support

            <*>  NVM Express block device

            [*]    NVMe multipath support

            [*]    NVMe hardware monitoring

           <*>  NVM Express over Fabrics FC host driver

           <*>  NVM Express over Fabrics TCP host driver

File systems  --->

       <*>  F2FS filesystem support

       [*]    F2FS Status Information (NEW)

       [*]    F2FS extended attributes (NEW)

       [*]    F2FS Access Control Lists (NEW)

       Network File Systems--->
        <*>   NFS client support
        <*>     NFS client support for NFS version 2
        <*>     NFS client support for NFS version 3
        [*]       NFS client support for the NFSv3 ACL protocol extension
        <*>     NFS client support for NFS version 4
        <*>   SMB3 and CIFS support (advanced network filesystem)

Kernel hacking  --->

      Compile-time checks and compiler options  --->

            [*]    Compile the kernel with debug info

            [*]    Provide GDB scripts for kernel debugging

注:高版本改成了

Kernel hacking  --->

      Compile-time checks and compiler options  --->

            Debug information (Disable debug information)  --->

                        (X)Generate DWARF Version 5 debuginfo

            [*]    Provide GDB scripts for kernel debugging

root@linux:/home/gsf/linux-5.10.3#make -j4 bzImage



3.2 启动内核

qemu启动内核后,如果想退出,可以在qemu中执行Ctlr+A,然后按x键。

也可以在ubuntu另一个终端 killall qemu-system-x86_64(不建议)。


  1. 仅rootfs启动

最简单的启动,资源很少,无disk,无网络。

qemu-system-x86_64 -kernel arch/x86_64/boot/bzImage -drive file=rootfs.f2fs,if=ide,format=raw -nographic -append "root=/dev/sda console=ttyS0"

启动完成后,用户名输入root,登录系统查看信息,f2fs已经挂载:

# cat /proc/mounts

/dev/root / f2fs rw,lazytime,relatime,background_gc=on,discard,no_heap,user_xattr,inline_xattr,acl,inline_data,inline_dentry,flush_merge,exte0

devtmpfs /dev devtmpfs rw,relatime,size=48612k,nr_inodes=12153,mode=755

  1. 挂载 scsi disk(格式化成ext4)启动
  • 制作ext4镜像
root@linux:/home/gsf/linux-5.10.3#dd if=/dev/zero of=ext4.img bs=1M count=256
root@linux:/home/gsf/linux-5.10.3# mkfs.ext4 ext4.img
  • 执行qemu命令
qemu-system-x86_64 -kernel arch/x86_64/boot/bzImage -drive file=rootfs.f2fs,if=ide,format=raw,id=myid0 --nographic -append "root=/dev/sda console=ttyS0" -hdb ext4.img

系统启动后,输入root用户名登录系统。

  • 修改挂载表
创建目录
#  mkdir /mnt/scsimp
并在/etc/fstab文件中增加一行:
/dev/sdb /mnt/scsimp ext4 defaults 0 0
  • reboot重新模拟出来的系统(不是自己的电脑系统),可以看到ext4已经挂载
# cat /proc/mounts
……
sysfs /sys sysfs rw,relatime 0 0
/dev/sdb /mnt/scsimp ext4 rw,relatime 0 0

  1. 挂载 scsi disk(格式化成ext4)+ nvme disk(格式化成f2fs)
  • 制作ext4镜像
root@linux:/home/gsf/linux-5.10.3#dd if=/dev/zero of=ext4.img bs=1M count=25
root@linux:/home/gsf/linux-5.10.3# mkfs.ext4 ext4.img
  • 制作nvme的模拟磁盘
root@linux:/home/gsf/linux-5.10.3#qemu-img create -f raw disk.qcow 1G
  • 执行qemu命令

qemu启动后,红字部分在/dev/目录下生成了nmve0,nvme0n1两个文件(如果没有生成,按第二节设置kenel编译config文件,打开nvme相关配置)。

qemu-system-x86_64 -kernel arch/x86_64/boot/bzImage -drive file=rootfs.f2fs,if=ide,format=raw,id=myid0 –nographic -append “root=/dev/sda console=ttyS0” -hdb ext4.img

-device nvme,drive=nvme1,serial=deadbeaf,num_queues=8 -drive file=disk.qcow,if=none,id=nvme1 -smp 4

  • 登录启动的linux系统
创建目录
#  mkdir /mnt/scsimp
#  mkdir /mnt/nvmemp
并在/etc/fstab文件中增加两行:
/dev/sdb /mnt/scsimp ext4 defaults 0 0
/dev/nvme0n1p1 /mnt/nvmemp f2fs defaults 0 0  -------后面会将disk.qcow格式化成f2fs,所以这里按f2fs挂载

格式化nvme disk

#


fdisk /dev/nvme0n1

Device contains neither a valid DOS partition table, nor Sun, SGI, OSF

or GPT disklabel

Building a new DOS disklabel. Changes will remain in memory only,

until you decide to write them. After that the previous content

won’t be recoverable.

Command (m for help):


n

Partition type

p primary partition (1-4)

e extended



p

Partition number (1-4):


1

First sector (32-2097151, default 32): ————回车,默认即可

Using default value 32

Last sector or +size{,K,M,G,T} (32-2097151, desfault 2097151):

————回车,默认即可

Using default value 2097151

Command (m for help):


w

The partition table has been altered.

Calling ioctl() to re-read partition table

[ 131.575409] nvme0n1: p1

格式化成功后,出现/dev/nvme0n1p1设备,这就是刚fdisk新建的分区

格式化新建的nvme分区

mkfs.f2fs -L nvmedisk /dev/nvme0n1p1

(这里也可以格式化成其他文件系统)

注:如果没有mkfs.f2fs工具,请参考 上面部分2.制作rootfs

  • reboot重启qemu模拟出来的系统(不是自己的电脑系统),登录后,可以看到scsi、nvme disk已经挂载
# cat /proc/mounts
……
sysfs /sys sysfs rw,relatime 0 0
/dev/sdb /mnt/scsimp ext4 rw,relatime 0 0
/dev/nvme0n1p1 /mnt/nvmemp f2fs rw,relatime 0 0

另外,还可以看到系统中有5个nvme队列。nvme0q0是管理队列。nvme0q1~4是IO队列每个核一个(我们的qemu命令指定了num_queues=8、smp 4参数)。

# cat /proc/interrupts
# cat /proc/interrupts
           CPU0       CPU1       CPU2       CPU3       
  0:        183          0          0          0   IO-APIC   2-edge      timer
  1:          0          0          9          0   IO-APIC   1-edge      i8042
……
 24:          6          0          0          0   PCI-MSI 65536-edge      nvme0q0
 25:          0          0          0         11   PCI-MSI 65537-edge      nvme0q1
 26:          0          0          0          0   PCI-MSI 65538-edge      nvme0q2
 27:          0          0          0          0   PCI-MSI 65539-edge      nvme0q3
 28:          0          0          0          0   PCI-MSI 65540-edge      nvme0q4



3.3 qemu参数说明

qemu-system-x86_64 -kernel arch/x86_64/boot/bzImage -drive file=rootfs.f2fs,if=ide,format=raw,id=myid0 –nographic -append “root=/dev/sda console=ttyS0” -hdb ext4.img -device nvme,drive=nvme1,serial=deadbeaf,num_queues=8 -drive file=disk.qcow2,if=none,id=nvme1 -smp 4 -s

-kernel 要运行的内核镜像

-drive 理解成一个虚拟的disk。

drive option之 file:代表该disk的文件,由“qemu-img create -f 格式”生成。

drive option之 if:interface,指定disk的接口,有ide, scsi, sd, mtd, floppy,

pflash, virtio, none这些类型。

drive option之 format:format:代码disk的file的格式,创建文件时由qemu-img create -f指定。

drive option之 id:一个字符串标识。有多个dirve时,通过id来识别用哪个drive。

–nographic:关闭图形调试,将打印信息输出到串口。

-append :kernel的命令行参数。

append之root:rootfs存储设备。

append之console:串口名称。

-hdb:创建一个hard disk。注意,字符串hdb不是/dev/hdb(这个个IDE disk),这里的hdb启动后,是/dev/sdb(scsi disk)。hdb image可以通过mkfs格式化成需要的文件系统。

-device:创建一个总线设备。将子参数drive=id指定的disk挂在总线下。

devie值num_queues:nvme的队列深度。

-smp:多核数量。

-s:监听gdb端口, gdb程序可以通过1234这个端口连上来。下文配置图形化调试需要



4. vscode 图形化调试环境配置

vscode中集成了GDB功能,我们可以用它来图形化的调试linux kernel



4.1 vscode配置

首先我们添加vscode的gdb配置文件(.vscode/launch.json):

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "kernel debug",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/vmlinux",
            "cwd": "${workspaceFolder}",
            "MIMode": "gdb",
            "miDebuggerPath":"/usr/bin/gdb-multiarch",
            "miDebuggerServerAddress": "localhost:1234"
        }
    ]
}

这里对几个重点参数做一些说明:

program: 调试的符号文件

miDebuggerPath:gdb的路径, 这里需要注意的是,由于我们是arm64内核,因此需要用gdb-multiarch来进行调试

miDebuggerServerAddress:对端地址,qemu会默认使用1234这个端口

配置完成之后,可以直接启动GDB, 连接上linux kernel



4.2 qemu配置

为了能够图形化调试,qemu启动时需要加上-s参数,默认使用1234端口



版权声明:本文为IT_xiao_bai0516原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。