版本信息

宿主机:ubuntu20.04.6LTS(FocalFossa)

虚拟机:ubuntu20.04.6LTS(FocalFossa)

安装宿主机的步骤省略,和通常的在vmware中安装虚拟机没有任何区别。

须要注意的是须要打开IntelVT-x

linux下img解压命令_linux解压常用命令_解压命令linux

假如启动虚拟机报告此平台不支持虚拟化的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设备

解压命令linux_linux下img解压命令_linux解压常用命令

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 ()

下断点

linux下img解压命令_解压命令linux_linux解压常用命令

(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。

解压命令linux_linux下img解压命令_linux解压常用命令

为了解决该问题,须要在安装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确认当前内核版本是否已切换至其他可用版本。

参考文章

Tagged:
Author

这篇优质的内容由TA贡献而来

刘遄

《Linux就该这么学》书籍作者,RHCA认证架构师,教育学(计算机专业硕士)。

发表回复