调试内核需要一个基本的文件系统,我们可以使用简单的 ramdisk来作为这个文件系统,如果,需要测试一些其它应用程序,我们还需要创建一个大一点根文件系统。
也就是内核启动时的initrd.img,可以使用busybox来制作这个小文件系统,源码目录的INSTALL文件有编译和安装的说明。
制作initrd.img
把 busybox拷贝到 initrd根目录,并切换到initrd根目录。
创建init: ln -s bin/busybox init
创建系统文件夹:mkdir dev etc proc sys
配置etc目录
.创建文件 etc/init.d/rcS,输入如下内容:
- #!/bin/sh
-
- mount proc
- mount -o remount,rw /
- mount -a
- clear
.创建文件 etc/fstab,输入如下内容:
- proc /proc proc defaults 0 0
- sysfs /sys sysfs defaults 0 0
- devtmpfs /dev devtmpfs defaults 0 0
.创建文件 etc/inittab,输入如下内容:
- ::sysinit:/etc/init.d/rcS
- ::askfirst:-/bin/sh
- ::restart:/sbin/init
- ::ctrlaltdel:/sbin/reboot
- ::shutdown:/bin/umount -a -r
- ::shutdown:/sbin/swapoff -a
5.创建img 磁盘文件
find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../initrd.img
磁盘文件系统同 initrd.img的一个最大区别是需要bootloader,制作磁盘文件系统大概需要这么几个步骤:
先生成一个有MBR记录的磁盘文件(hda.img),文件系统是ext4,并mount.
安装grub到磁盘文件。
下载一个根文件系统(如:debootstrap --arch=i386 focal focal-rootfs)。
拷贝到磁盘文件,并做好配置。
文件系统配置
1:grub: 添加启动程序,设置sda1为rw, 下面的init是systemd的初始化进程。
linux /boot/bzImage rw text root=/dev/sda1 init=/usr/sbin/init
2:设置root密码,系统登陆时需要输入的密码
3: 配置自动登陆,或者其它登陆账号。
vim lib/systemd/system/getty@.service,修改/sbin/agetty的输入参数.
添加 -a root[或者其它账号], 实现自动登陆。
使用initrd.img
qemu-system-x86_64 -kernel bzImage -boot c -m 1024 -initrd initrd.img -append "console=ttyS0, 115200" -serial stdio
-serial stdio: 把控制台重定向到当前终端,还可以这样来配置控制台:
"console=ttyS0,115200 console=tty0" -serial file:kernel.log
使用虚拟机系统的终端,运行日志写到当前目录下的 kernel.log
使用文件系统
qemu-system-x86_64 -hda hda.img -chardev stdio,id=terminal,mux=on -device isa-debugcon,iobase=0x402,chardev=terminal -serial chardev:terminal
qemu + gdb 调试内核
1:运行qemu命令时,后面添加 "-s -S",这样虚拟机启动后会暂停 ——,如:
qemu-system-x86_64 ...... -serial stdio -s -S
2:gdb加载对应内核的vmlinux文件,在gdb命令行输入:
(gdb) break start_kernel
(gdb) target remote :1234
(gdb) c
3:qemu运行,并停止在 start_kernel处,此时可以使用gdb的命令来单步执行,查看寄存器的值。
4:qemu在运行期间,也可以中断gdb,设置新的断点。
来源于网络,略作修改。
- #!/bin/bash
- # Echo commands to stdout as they execute.
- set -x
- set -eE
- clean () {
- rm .hda.img || true
- sudo umount tmpmnt || true
- rm -rf tmpmnt || true
- sudo losetup -d ${HDA_LOOP_DEV} || true
- }
-
- clean
- # Create an empty 1G disk image, 自行调整大小。
- truncate -s1G .hda.img
-
- /sbin/parted -s .hda.img mktable msdos
- /sbin/parted -s .hda.img mkpart primary ext4 1 "100%"
- /sbin/parted -s .hda.img set 1 boot on
-
- HDA_LOOP_DEV=$(sudo losetup -Pf --show .hda.img)
- FS_LOOP_DEV="${HDA_LOOP_DEV?}p1"
- sudo mkfs -t ext4 -v "${FS_LOOP_DEV?}"
-
- mkdir tmpmnt
- sudo mount "${FS_LOOP_DEV?}" tmpmnt
- sudo chown -R ${USER?} tmpmnt
-
- #安装grub
- mkdir -p tmpmnt/boot/grub
- echo "(hd0) ${HDA_LOOP_DEV?}" >tmpmnt/boot/grub/device.map
- sudo grub-install -v --directory=/usr/lib/grub/i386-pc \
- --boot-directory=tmpmnt/boot ${HDA_LOOP_DEV?} 2>&1
-
- cat >tmpmnt/boot/grub/grub.cfg <<EOF
- serial
- terminal_input serial
- terminal_output serial
- set root=(hd0,1)
- linux /boot/bzImage rw root=/dev/sda1 init=/usr/sbin/init
- boot
- EOF
-
- #拷贝内核和文件系统,修改为自己提供内容
- cp bzImage tmpmnt/boot/bzImage
-
- # Download a basic Debian system
- if [ ! -d focal-rootfs ]; then
- sudo debootstrap --arch=i386 focal focal-rootfs
- fi
- sudo cp -av focal-rootfs/* tmpmnt/
- mv .hda.img hda.img
- clean
---
欢迎大家来我的公众号交流: 般若程序蝉