系列文章目录
Linux内核学习
Linux 知识
QEMU 虚拟机
Linux 调试视频
近阶段补充知识
WSL Ubuntu
文章目录
- 系列文章目录
- 一、WSL
- 二、QEMU
- 1、安装
- 2、退出
- 3、识别 USB
- 三、构建根文件系统
- 1、下载 BusyBox
- 2、编译
- 3、构建
- 文件目录:
- Makefile
- init
- 四、内核编译
- 1、下载
- 2、构建
- 五、调试
- 1、GDB 命令调试
- 2、VSCode 调试
- (1)解决代码报红
- (2)launch.json
- 六、内核启动参数
- 引导参数
- __setup 宏
- 七、linux 知识补充
- 1、boot 目录
- 2、/lib/modules
- 示例
- 八、VirtualBox
一、WSL
# 查看系统状态
wsl -l -v
# 关闭系统
wsl --shutdown Ubuntu-18.04
# 导出当前Linux的镜像
wsl --export Ubuntu-18.04 D:\wsl-ubuntu\Ubuntu-18.04.tar
# 注销当前的系统
wsl --unregister Ubuntu-18.04
# 从镜像重新导入系统
wsl --import Ubuntu-18.04 D:\wsl-ubuntu\Ubuntu-18.04 D:\wsl-ubuntu\Ubuntu-18.04.tar # 设置默认登录用户
C:\Users\<user name>\AppData\Local\Microsoft\WindowsApps\ubuntu1804.exe config --default-user xiaoming
二、QEMU
1、安装
sudo apt install qemu-system-arm qemu-system-x86
2、退出
先按 Ctrl + A ,再按 X
3、识别 USB
QEMU 调试 USB 环境搭建
qemu下的USB直通功能介绍
虚机支持虚拟USB存储设备
qemu: usb存储设备仿真
三、构建根文件系统
1、下载 BusyBox
BusyBox 官网 下载
2、编译
make menuconfig
# 配置选择:
# settings => Build Options => Build static binary (no shared libs) make -j12
make install# 安装的文件在当前 _install 下
BusyBox编译时出错
3、构建
文件目录:
# 制作RamFs(RootFs文件夹,主要为busybox和init文件)
├── bzImage
├── initramfs.img
├── Makefile
└── rootfs├── bin├── init├── linuxrc -> bin/busybox├── sbin└── usr
Makefile
bzImagePath=/home/liuqz/work/linux/linux-6.12.7/arch/x86/bootimage:cp ${bzImagePath}/bzImage ./ramfs:cd ./rootfs && find . -print0 | cpio -ov --null --format=newc | gzip -9 > ../initramfs.imgrun:qemu-system-x86_64 \-kernel ${bzImagePath}/bzImage \-initrd initramfs.img \-m 1G -nographic \-device qemu-xhci \-device usb-bot \-append "earlyprintk=serial,ttyS0 console=ttyS0 nokaslr"debug:qemu-system-x86_64 \-kernel ${bzImagePath}/bzImage \-initrd initramfs.img \-m 1G -nographic \-device qemu-xhci \-device usb-bot \-S -s \-append "earlyprintk=serial,ttyS0 console=ttyS0 nokaslr"# -gdb tcp::9000 # 指定 gdb 服务端点号
# -S 在开始时阻塞 CPU 运行
# -s 开启 GDB 服务,端口 1234
# nokaslr 4.x 以后版本禁止内核地址空间布局随机
-usb
-device usb-storage,drive=drive_id
-device usb-uas
-device usb-bot
-device usb-host,hostbus=bus,hostaddr=addr
-device usb-host,vendorid=vendor,productid=product
- “-usb” 使能usb总线,如果系统已添加usb总线,则不需要这个参数
- “usb-storage” 仿真使用bulk-only传输协议的虚拟设备(绝大部分u盘采用的传输方式),只支持单一逻辑单元
- “usb-uas” 仿真使用UAS(USB attached SCSI)传输协议的虚拟设备,支持多逻辑单元(MLUN)
- “usb-bot” 也是仿真使用bulk-only传输协议的虚拟设备,支持多逻辑单元
- “usb-host” 连接实际的usb存储设备
init
#!/bin/busybox sh/bin/busybox echo "Hello Linux"/bin/mount -t proc none /proc/bin/mknod /dev/tty2 c 4 2
/bin/mknod /dev/tty3 c 4 3
/bin/mknod /dev/tty4 c 4 4/bin/busybox sh
四、内核编译
1、下载
Linux kernel 官网
如何下载Linux Kernel历史版本
2、构建
# make help
# sudo apt install flex bison
make x86_64_defconfig
make menuconfig
# 优化可选
# Device Drivers => Sound card support
Kernel hacking => Compile-time checks and compiler options => => Debug information => Rely on the toolchain's implicit default DWARF version
Kernel hacking => printk and dmesg options => Default console loglevel => 15# sudo apt-get install libelf-dev
make -j12
编译后文件 System.map 和 vmlinux 。
默认的内核编译命令会编译使能的模块,但生成的ko文件分散在各个文件夹内 可在编译时传入参数 INSTALL_MOD_PATH
,指定内核模块的存储位置,方便后续存放至 rootfs 内
make ARCH=arm64 LLVM=1 INSTALL_MOD_PATH=/home/zyp/workplace/linux-5.15.163 modules_install -j16
make INSTALL_MOD_PATH=/home/zyp/workplace/linux-5.15.163 modules_install -j16
五、调试
1、GDB 命令调试
# 启动内核
make debug#调试内核
gdb vmlinux # 根下的vmlinux
# 连接远端gdb端口
target remote :1234
# 设置断点
break start_kernel # 可通过System.map查看断点地址和信息
continue
GDB常用命令
命令 | 含义 |
---|---|
r | 重新执行 |
q | 退出gdb |
n | 下一步 |
c | 继续执行 |
b 普通断点 | 打断点 【普通断点】b file.c :行号 【条件断点】b file.c : 行号 if num == 2 【查看断点】info b 【删除断点】del 2 【禁用/启用】disable / enable 2 |
watch 观察断点 | 【监控num】watch num 当被监控变量/表达式的值发生改变时,程序停止运行 【查看观察断点】info watchpoints 监控局部变量num:一旦num失效,则监控操作也随即失效。 监控指针变量*p: watch *p表示监控p所指数据的变化情况;watch p表示监控p指针本身是否改变指向。 监控数组a[10]中的元素:watch a表示只要数组a中元素发生改变,程序就会停止执行。 |
catch 捕捉断点 | |
bt | 查看函数调用堆栈信息,用于发生段错误时,追踪错误 |
display | 【频繁查看变量】display num 程序每暂停一次(遇断点或单步调试),自动打印变量num值 【禁用/启用】disable / enable display num |
list | 默认显示当前行的上5行和下5行的源代码 |
2、VSCode 调试
(1)解决代码报红
- 生成 compile_commands.json
# 生成 compile_commands.json
./scripts/clang-tools/gen_compile_commands.py
- 配置 c_cpp_properties.json
.vscode
下c_cpp_properties.json
可以使用 CTRL + SHIFT + P 选择 C/C++: Edit Configurations,创建 c_cpp_properties.json 文件。
// c_cpp_properties.json
{"configurations": [{"name": "Linux","includePath": ["${workspaceFolder}/**"],"defines": [],"compilerPath": "/usr/bin/gcc","cStandard": "c17","cppStandard": "c++14","intelliSenseMode": "linux-clang-x64","compileCommands": "${workspaceFolder}/compile_commands.json"}],"version": 4
}
(2)launch.json
.vscode
下 launch.json
,配置调试信息。
// launch.json
{// 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387"version": "0.2.0","configurations": [{"name": "gdb debug","type": "cppdbg","request": "launch",// "miDebuggerServerAddress": "172.18.25.30:1234","miDebuggerServerAddress": "127.0.0.1:1234","program": "${workspaceRoot}/vmlinux","args": [],"stopAtEntry": false,"cwd": "${workspaceFolder}","environment": [],"externalConsole": false,"logging": {"engineLogging": false},"MIMode": "gdb"}]
}
六、内核启动参数
Linux内核启动配置项
Linux操作系统内核启动参数详解
uboot如何向内核传递参数
内核启动参数详解配合代码分析
U-Boot与kernel之间的参数传递机制完全解析
# 设置U-Boot环境变量
setenv bootargs 'console=ttyS0,115200 root=/dev/nfs nfsroot=192.168.1.100:/nfsroot/rootfs ip=192.168.1.101:192.168.1.100:192.168.1.1:255.255.255.0::eth0:off'
# 保存环境变量
saveenv
# 启动内核
bootm 0x10000
引导参数
- root:指定根文件系统的位置。例如,root=/dev/sda1表示根文件系统在第一个 SATA 硬盘的第一个分区上。
- ro/rw:分别表示以只读或读写方式挂载根文件系统。通常在启动过程中先以只读方式挂载,在文件系统检查完成后切换为读写方式。
- init:设置内核执行的初始化进程名,如果该项没有设置,内核会按顺序尝试 /init , /sbin/init,/etc/init,/bin/init, /bin/sh,如果所有的都没找到,内核会抛出 kernel panic:的错误。
- console:指定控制台设备。例如,console=ttyS0,115200表示使用串口 0 作为控制台,波特率为 115200。
__setup 宏
Linux内核__setup 宏的作用及分析
static int __init root_dev_setup(char *line)
{strscpy(saved_root_name, line, sizeof(saved_root_name));return 1;
}__setup("root=", root_dev_setup);
七、linux 知识补充
1、boot 目录
Linux中 /boot 目录介绍
Linux中/boot目录
- config-4.14.0-kali3-amd64
当前 Linux 系统的 kernel 配置文件,可以使用下面指令查看。
cat /boot/config-4.14.0-kali3-amd64 | mor
- initrd.img-4.14.0-kali3-amd64(cpio格式)
initrd 全名 initial ram disk,启动系统所需加载的虚拟磁盘。它是 vmlinuz 的映像文件。 - vmlinuz-4.14.0-kali3-amd64
linux 的正式内核。 - System.map-4.14.0-kali3-amd64
内核符号映射表,顾名思义就是将内核中的符号(也就是内核中的函数)和它的地址能联系起来的一个列表。 - grub
引导加载程序相关的文件。
2、/lib/modules
/lib/modules
目录通常包含了 Linux 内核的模块文件。这些模块可以在需要时动态加载到内核中。自动加载驱动程序通常意味着当某些事件发生时,系统会自动加载相应的内核模块。
在Linux系统中,可以使用 modprobe
命令来自动加载模块。modprobe 基于内核配置中的依赖关系和模块参数来决定是否自动加载模块。
如果你需要在系统启动时自动加载特定的内核模块,你可以编辑 /etc/modules-load.d目录下的配置文件或者在 /etc/modules 文件中直接添加模块名。
示例
例如,如果你想自动加载名为 mymodule 的模块,你可以执行以下步骤之一:
- 创建一个新的配置文件 /etc/modules-load.d/mymodule.conf 并在其中写入模块名:
mymodule
- 编辑 /etc/modules 文件,在文件末尾添加模块名:
mymodule
在系统下次启动时,这些模块将会自动通过 modprobe 或 insmod 加载。
系统启动后自动加载 modules
另外,你也可以通过 udev
规则来管理设备节点,在特定事件(如插入某个设备)发生时自动执行 modprobe
命令。
八、VirtualBox
在 Linux 上的 VirtualBox 中从虚拟机访问 USB | Linux 中国
如何在 VirtualBox 中启用和访问 U 盘 | Linux 中国
☆