版本信息
宿主机:ubuntu20.04.6LTS(FocalFossa)
虚拟机:ubuntu20.04.6LTS(FocalFossa)
安装宿主机的步骤省略,和通常的在vmware中安装虚拟机没有任何区别。
须要注意的是须要打开IntelVT-x
假如启动虚拟机报告此平台不支持虚拟化的IntelVT-x/EPT.不使用虚拟化的IntelVT-x/EPT,是否继续,参考下边的文章解决.
宿主机安装QEMU/KVM和Virsh
Virsh是VirtualShell的简写,是一个用于管理虚拟机的命令行工具。你可以使用Virsh创建、编辑、启动、停止、关闭和删掉VM。Virsh目前支持KVM,LXC,Xen,QEMU,OpenVZ,VirtualBox和VMwareESX。这儿我们使用Virsh管理QEMU/KVM虚拟机。
在安装之前linux下img解压命令,首先要确认你的CPU是否支持虚拟化技术。使用grep查看cpuinfo是否有”vmx”(Intel-VT技术)或”svm”(AMD-V支持)输出:
egrep "(svm|vmx)" /proc/cpuinfo
个别CPU机型在默认情况下,BIOS中可能禁用了VT支持。我们须要再检测BIOS设置是否启用了VT的支持。使用kvm-ok命令进行检测:
sudo apt install cpu-checker
kvm-ok
假如输出为:
INFO: /dev/kvm exists
KVM acceleration can be used
证明CPU的虚拟化支持早已在BIOS中启用。
运行下边的命令安装QEMU/KVM和Virsh:
sudo apt install qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virtinst virt-manager
检测libvirt守护程序是否早已启动:
sudo systemctl is-active libvirtd
active
若果没有输出active,运行下边的命令启动libvertd服务:
sudo systemctl enable libvirtd
sudo systemctl start libvirtd
在宿主机中安装qemu虚拟机
创建一个虚拟机镜像,大小为40G,qow2格式动态分配c盘占用空间。
qemu-img create -f qcow2 ubuntutest.img 40G
创建虚拟机系统,安装操作系统:
qemu-system-x86_64
-name ubuntutest
-smp 2
-m 4096
-hda ubuntutest.img
-cdrom ubuntu-20.04.6-live-server-amd64.iso
-boot d
根据步骤,配置安装即可linux命令vi,这一步和正常的虚拟机安装没有哪些区别。
注意这儿我没有添加-enable-kvm嵌入式linux论坛,这可能会影响gdb的软件断点。
配置上网方案1:自建tap网卡NAT上网
宿主机创建TAP设备
sudo ip tuntap add dev tap0 mode tap
sudo ip addr add 192.168.100.1/24 dev tap0
sudo ip link set tap0 up
宿主机配置IP转发及NAT规则
sudo sysctl -w net.ipv4.ip_forward=1
sudo iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -o ens33 -j MASQUERADE
sudo iptables -A FORWARD -i tap0 -j ACCEPT
启动带TAP的QEMU
qemu-system-x86_64
-enable-kvm
-m 4096
-drive file=./ubuntutest.img
-boot d
-net nic -net tap,ifname=tap0,script=no,downscript=no
配置虚拟机的网路为192.168.100.0/24网关中的任意一个地址(比如192.168.100.10)
打开netplan的配置文件,更改地址后,使用sudonetplanapply重启网路。
# This is the network config written by 'subiquity'
network:
ethernets:
ens3:
dhcp4: no
addresses:
- 192.168.100.10/24
routes:
- to: default
via: 192.168.100.1
nameservers:
addresses: [8.8.8.8]
version: 2
借助virbr0实现nat上网
创建并配置bridge.conf
sudo mkdir -p /etc/qemu
sudo vim /etc/qemu/bridge.conf
内容示例:
allow virbr0 # 若使用libvirt默认桥接接口
接出来启动时指定使用virbr0bridge上网。
qemu-system-x86_64
-enable-kvm
-m 4096
-drive file=./ubuntutest.img -boot d
-netdev bridge,id=net0,br=virbr0
-device virtio-net-pci,netdev=net0
配置虚拟机网路时,配置和virbr0一个网关的,即192.168.122.0/24(比如192.168.122.10)
下载linux内核而且编译安装编译依赖
首先我们须要安装编译内核用到的依赖包,我是在宿主机上编译linux内核代码的,因而下边的句子直接在宿主机上执行。
sudo apt install libncurses5-dev libssl-dev bison flex libelf-dev gcc make openssl libc6-dev dwarves
下载linux内核代码并建立
下载Linux内核代码,这儿我使用的是5.10.209版本
使用下边的句子makekernel编译参数:
sudo make menuconfig
为了建立才能调试的内核,我们须要配置以下几个参数。
这个选项的菜单路径为:
Kernel hacking --->
Compile-time checks and compiler options --->
[*] Compile the kernel with debug info
也可以直接在.config中设置CONFIG_DEBUG_INFO。
CONFIG_DEBUG_INFO=y
也可以在.config中设置:
CONFIG_FRAME_POINTER=y
CONFIG_GDB_SCRIPTS=y
CONFIG_DEBUG_INFO_REDUCED=n
Kernel hacking --->
Generic Kernel Debugging Instruments --->
[*] KGDB: kernel debugger
CONFIG_KGDB=y
CONFIG_RANDOMIZE_BASE的位置在如下位置可以找到:
Processor type and features --->
Randomize the address of the kernel image (KASLR)
或则直接在.config中添加下边的句子
CONFIG_RANDOMIZE_BASE=n
KASLR会修改引导时放置内核代码的基地址。假如你在内核配置中启用了KASLR(CONFIG_RANDOMIZE_BASE=y),则难以从gdb设置断点。设置完必要的内核参数后linux下img解压命令,我们开始编译内核:
sudo make -j8
sudo make INSTALL_MOD_STRIP=1 modules_install
sudo make install
makemodules_install会将module文件安装到/lib/modules/5.10.209,而且最好添加上INSTALL_MOD_STRIP=1,否则initrd.img容积会很大。
编译大约须要30G空间,因而须要事先打算好>=30G的c盘。
这种步骤执行完毕以后,我们就得到了须要的linux内核镜像bzImage(vmlinuz)和initrd.img
xu@xu-dev:~/work/linux-5.10.209$ ls /boot/ -alh |grep 5.10.209
-rw-r--r-- 1 root root 243K 4月 20 19:34 config-5.10.209
lrwxrwxrwx 1 root root 19 4月 20 19:34 initrd.img -> initrd.img-5.10.209
-rw-r--r-- 1 root root 60M 4月 20 19:34 initrd.img-5.10.209
-rw-r--r-- 1 root root 5.5M 4月 20 19:34 System.map-5.10.209
lrwxrwxrwx 1 root root 16 4月 20 19:34 vmlinuz -> vmlinuz-5.10.209
-rw-r--r-- 1 root root 14M 4月 20 19:34 vmlinuz-5.10.209
编译的产物介绍
在Linux内核编译过程中,生成的文件按照功能可分为以下几类,以下是详尽介绍及对应的文件作用与来源:
核心可执行文件vmlinuxzImage
**与**bzImage
uImage引导相关文件System.mapinitrd.img
**或**initramfs
内核模块文件.ko
**文件(KernelObject)**
配置文件与日志.configvmlinux.lds中间文件与工具生成文件.o
**与**built-in.o
设备树文件(.dtb)启动管理与版本标示vmlinuz-config-总结对比表文件类型关键文件作用生成命令
核心镜像
vmlinux
,bzImage
内核执行与引导
make
,makebzImage
模块
.ko
动态扩充内核功能
makemodules
配置
.config
记录编译选项
makemenuconfig
引导支持
initrd.img
初期启动依赖加载
mkinitramfs
符号映射
System.map
调试符号地址映射
手动生成
设备树
.dtb
嵌入式硬件描述
makedtbs
内核debug
在获取内核镜像bzImage和initrd.img以后,就可以使用其启动qemu虚拟机。
注意我这儿的调试是使用qemu的-kernel和-initrd去直接加载内核,而没有使用grub去加载内核。
我的qemu的启动脚本如下所示:
qemu-system-x86_64
-smp 2
-m 4096
-S -s
-drive file=/home/xu/work/ubuntutest.img
-netdev bridge,id=net0,br=virbr0
-device virtio-net-pci,netdev=net0
-kernel /home/xu/work/kernel-with-rwx/bzImage
-initrd /home/xu/work/kernel-with-rwx/initrd.img-5.10.209
-append "root=/dev/mapper/ubuntu--vg-ubuntu--lv ro maybe-ubiquity console=ttyS0
-nographic
里面提及,还有一种是使用grub启动内核,相对要麻烦一点,须要把宿主机上的内核拷贝到虚拟机上,并执行makemodules_install和makeinstall,之后启动时使用-bootd从硬碟加载内核。
qemu-system-x86_64
-enable-kvm
-smp 2
-m 4096
-drive file=./ubuntutest.img -boot d
-netdev bridge,id=net0,br=virbr0
-device virtio-net-pci,netdev=net0
不过我认为使用-kernel和-initrd更为便捷,也愈发推荐。
接出来启动gdb调试,使用另一个终端打开gdb:
xu@xu-dev:~/work/linux-5.10.209$ gdb vmlinux -q
Reading symbols from vmlinux...
warning: File "/home/xu/work/linux-5.10.209/scripts/gdb/vmlinux-gdb.py" auto-loading has been declined by your `auto-load safe-path' set to "$debugdir:$datadir/auto-load".
To enable execution of this file add
add-auto-load-safe-path /home/xu/work/linux-5.10.209/scripts/gdb/vmlinux-gdb.py
line to your configuration file "/home/xu/.gdbinit".
To completely disable this security protection add
set auto-load safe-path /
line to your configuration file "/home/xu/.gdbinit".
For more information about this security protection see the
"Auto-loading safe path" section in the GDB manual. E.g., run from the shell:
info "(gdb)Auto-loading safe path"
使用gdb远程联接:
(gdb) target remote :1234
Remote debugging using :1234
0x000000000000fff0 in exception_stacks ()
下断点
(gdb) b start_kernel
Breakpoint 1 at 0xffffffff82daad61: file init/main.c, line 847.
继续执行,触发断点:
(gdb) c
Continuing.
Thread 1 hit Breakpoint 1, start_kernel () at init/main.c:847
单步调试:
847 {
(gdb) n
851 set_task_stack_end_magic(&init_task);
(gdb) n
852 smp_setup_processor_id();
(gdb) n
855 cgroup_init_early();
(gdb)
问题证书找不到
CC [M] kernel/kheaders.o
CC certs/system_keyring.o
make[1]: *** No rule to make target 'debian/canonical-certs.pem', needed by 'certs/x509_certificate_list'. Stop.
make: *** [Makefile:1832: certs] Error 2
解决办法:
1.更改CONFIG_SYSTEM_TRUSTED_KEYS
更改前:原变量有值
CONFIG_SYSTEM_TRUSTED_KEYS=”debian/canonical-certs.pem”
更改后:将该变量赋空值
CONFIG_SYSTEM_TRUSTED_KEYS=””
2.更改CONFIG_SYSTEM_REVOCATION_KEYS(可选)
假如CONFIG_SYSTEM_REVOCATION_KEYS的值不为空的话,也将其赋空值。
更改前:原变量有值
CONFIG_SYSTEM_REVOCATION_KEYS=”debian/canonical-revoked-certs.pem”
更改后:将该变量赋空值
CONFIG_SYSTEM_REVOCATION_KEYS=””
内核逗留在“loadinginitialramdisk”很长时间而且启动以后kernelcrash报告引导内核晨报错Kernelpanicnotsyncing:Systemisdeadlockedonmemory
编译内核的过程中,当安装内核模块未使用INSTALL_MOD_STRIP=1时,会造成initrd文件过大,致使启动时卡在解压initrd上耗费过度的时间。
比如这儿,我的initrd.img是1.2G。
为了解决该问题,须要在安装module的时侯添加INSTALL_MOD_STRIP=1
sudo make INSTALL_MOD_STRIP=1 modules_install
sudo make install
kernelcrash报告引导内核晨报错Kernelpanicnotsyncing:Systemisdeadlockedonmemory
这个问题和initrd.img相关。一种方法是通过减少initrd.img解决,还有一种方法就是通过调大虚拟机显存解决。
gdb软件中断难以触发,硬件中断可以触发
qemu假如启动时指定了-enable-kvm,会造成该问题。
假如启动的时侯指定了-enable-kvm,则设置断点时须要使用硬件断点,比如
hb start_kernel
PS怎么清除内核编译产物
若在编译并安装Linux内核后希望卸载,以下是具体操作步骤及注意事项:
步骤1:确认内核版本及安装路径查看已安装的内核版本
:
ls /boot | grep vmlinuz # 列出所有内核文件
uname -r # 查看当前正在运行的内核版本(避免误删)
确认自动编译安装的内核版本
:
假定目标卸载的内核版本为5.18.8,需确保其不在uname-r的输出中,否则删掉后可能造成系统未能启动。
步骤2:自动删掉内核相关文件
自动编译安装的内核文件分散在多个目录中,需按路径逐一删掉:
删掉/boot目录下的内核文件
:
sudo rm -rf /boot/vmlinuz-5.18.8
sudo rm -rf /boot/initrd.img-5.18.8
sudo rm -rf /boot/config-5.18.8
sudo rm -rf /boot/System.map-5.18.8
删掉内核模块目录
:
sudo rm -rf /lib/modules/5.18.8
删掉内核源码目录(可选)
:
sudo rm -rf /usr/src/linux-5.18.8
清除initramfs残留
:
sudo rm -rf /var/lib/initramfs-tools/5.18.8
步骤3:更新GRUB引导配置
删掉内核后需更新GRUB,防止残留无效启动项:
sudo update-grub
步骤4:重启系统
sudo reboot
重启后通过uname-r确认当前内核版本是否已切换至其他可用版本。
参考文章