一、KConfig、Make
三者之间的关系如下:当我们在内核源码目录下输入make menuconfig时,在出现的菜单界面中选择一项时,它会自动更新.config相应项的值。如果我们没有选择,则会在.config问下插入一行注释。类似于# CONFIG_SERIAL_NONSTANDARD is not set,当我们输入make时,根据makefile文件来编译,makefile文件中的变量值则由.config来进行赋值操作。仅仅只在kconfig中添加选项,只会在菜单界面中显示,即使此时选择y或m,也不会编译文件。还需要在makefile文件中按照规定添加相应行才能进行编译。简单图解如下:
kconfig------->.config---------->makefile
1、内核中加入自己的模块
编写了 mytest.c 的文件,这里不关心 mytest.c 的内容。如果想把 mytest.c 编译到内核中,需要按照以下的步骤来完成:
- 将 mytest.c 放到任何一个目录中,这个目录只要求已存在 Kconfig 和 Makefile 中,比如源码根目录 /arch/arm/ 目录中。
- 在这个目录的 Kconfig 中添加
config MY_TEST
bool “My Test”
- 在 Makefile 中添加
obj-$(CONFIG_MY_TEST) += mytest.o
- 在 .config 中可以添加 CONFIG_MY_TEST = y 来选中或者在执行 make menuconfig 时,找到显示名为 My Test 的选项,使用空格选中
总而言之,就是如果需要向系统内核中添加一个功能,那么首先定义一个配置项对应于这个功能,添加到特定的 Kconfig 文件中。然后在 Makefile 里,定义这个配置项需要编译哪些文件。最后就可以通过 make menuconfig 或者直接修改 .config 来使能这个配置项。
二、uboot
git clone https://source.denx.de/u-boot/u-boot.git
uboot研读笔记 | 01 - 下载uboot源码并使用VSCode远程查看源码、编译uboot(2012.04.01版本)
环境变量的优先级
命令传参>环境变量>uboot源码中的设置
史上最全的Uboot常用命令汇总(超全面!超详细!)收藏这一篇就够了
uboot github
uboot docs
uboot源码下载以及编译
三、Linux内核
1、内核下载
2、错误解决
【错误记录】编译 Linux 内核报错 ( Unable to find the ncurses package. )
make menuconfig错误: /bin/sh: 1: flex: not found 和 /bin/sh: 1: bison: not found
fatal error: libelf.h: No such file or directory 解决方案
【问题解决】fatal error: openssl/xxx.h: 没有那个文件或目录
Linux内核编译错误:make[1]: *** 没有规则可制作目标“debian/canonical-certs.pem”,由“certs/x509_certificate_list” 需求。 停止
Cannot generate ORC metadata for CONFIG_UNWINDER_ORC=y, please install libelf-dev
3、docker ubuntu环境
sudo apt-get install make
4、GDB
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
sudo apt-get update
sudo apt-get -y --force-yes install gdb
gdb -v
sudo apt-get -y --force-yes install gdbserver
sudo add-apt-repository --remove ppa:ubuntu-toolchain-r/test
sudo apt-get update
5、QEMU
6、vscode
在windows通过VS Code开发Linux内核驱动程序
linux驱动之调试技巧— 应用程序远程gdb+vscode调试应用程序, 串口kgdboc调试.ko驱动程序
vscode + gdb 远程调试 linux 内核源码(附视频)
{
"files.exclude": {
"**/.git": true,
"**/.svn": true,
"**/.hg": true,
"**/CVS": true,
"**/.DS_Store": true,
"**/Thumbs.db": true,
"arch/[^ix]*": true,
"arch/i[a-z]*": true,
"arch/x[a-z]*": true,
"arch/x86*": true,
"include/asm-[^ixg]*": true,
"include/asm-i[a-z]*": true,
"include/asm-x[a-z]*": true,
"include/asm-x86*": true,
"Documentation": true
},
"search.exclude": {
"**/node_modules": true,
"**/bower_components": true,
"**/*.code-search": true
}
}
7、实战步骤
(1) 内核配置
make menuconfig 配置好的文件保存为.config文件,直接以当前运行的X86平台的配置作为参考(cp /boot/config-2.6.18.el5 .config),若要配置2440开发板,则可以参考arch/arm/configs/s3c2410_defconfig 将其拷贝到内核源代码根目录(cp arch/arm/configs/s3c2410_defconfig .config)
注意:就算你完全用别的配置文件,也要执行make menuconfig,就算你什么也不改变,退出时也要记得选保存,这样才会有.config文件
开始内核调试
Kernel hacking
=> Compile-time checks and compiler options
=> Debug information
=> Rely on the toolchain’s implicit default DWARF version
选择 Rely on the toolchain’s implicit default DWARF version 打开调试
(2) 内核映像文件制作
关于bzImage、vmlinux、vmlinuz等内核映像文件
zImage、bzImage、uImage、vmlinuz、vmlinux
# 制作RamFs(RootFs文件夹,主要为busybox和init文件)
├── bzImage
├── initramfs.img
├── Makefile
└── rootfs
├── bin
├── init
├── linuxrc -> bin/busybox
├── sbin
└── usr
(a)init 文件
#!/bin/busybox sh
/bin/busybox echo "Hello Linux"
/bin/mount -t proc none /proc
/bin/busybox sh
或者参考 超级详细讲解根文件系统rootfs的制作 进行制作Rootfs
(2) QEMU调试参数
cmdline:nokaslr (禁用内核地址空间布局随机)
-S 在开始时阻塞 CPU 执行
-s 开启 GDB 服务器,端口 1234
-gdb tcp::1234 开启 GDB 服务器,端口可以自己指定
qemu-system-x86_64 \
-kernel bzImage \
-initrd initramfs.img \
-m 1G \
-nographic \
-append "earlyprintk=serial,ttyS0 console=ttyS0 nokaslr" \
-S \
-gdb tcp::1234
(a)运行脚本
Makefile 中 ramfs 目标用来创建 initramfs.img,run 目标用来引导新建的内核和根文件系统。
ramfs:
cd ./rootfs && find . -print0 | cpio -ov --null --format=newc | gzip -9 > ../initramfs.img
run:
qemu-system-x86_64 \
-kernel bzImage \
-initrd initramfs.img \
-m 1G \
-nographic \
-append "earlyprintk=serial,ttyS0 console=ttyS0"
(3) GDB 命令调试
target remote:1234
break start_kernel
continue
step
# 启动内核
make run
#调试内核
gdb vmlinux # 根下的vmlinux
# 连接远端gdb端口
target remote :1234
# 设置断点
break start_kernel # 可通过System.map查看断点地址和信息
continue
gdb init
(4)vscode 界面调试
(a)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"
}
]
}
(b)c_cpp_properties.json
- 生成 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
}
(5)QEMU 命令
CTAL + A,然后按 x 键
8、前置知识
(1)多个版本GCC编译器的安装
9、Linux 0.11
Linux 0.11启动过程分析(一)
Linux 0.11 fork 函数(二)
Linux0.11 缺页处理(三)
Linux0.11 根文件系统挂载(四)
Linux0.11 文件打开open函数(五)
Linux0.11 execve函数(六)
Linux0.11 80X86知识(七)
Linux0.11 内核体系结构(八)
Linux0.11 系统调用进程创建与执行(九)
Linux0.11 进程切换(十)
Linux0.11 管道(十一)
Linux0.11 信号(十二)
10、Linux 内核设计与实现
11、深入理解 Linux 内核
四、内核驱动
1、Camera 与 V4L2
【Camera基础(一)】Camera摄像头工作原理及整机架构
【Camera基础(二)】摄像头驱动原理和开发&&V4L2子系统驱动架构
基于ZedBoard的Webcam设计(一):USB摄像头(V4L2接口)的图片采集
基于ZedBoard的Webcam设计(二):USB摄像头图片采集+QT显示
基于ZedBoard的Webcam设计(三):视频的采集和动态显示
基于ZedBoard的Webcam设计(四):MJPG编码和AVI封装
基于ZedBoard的Webcam设计(五):x264编码在zedboard上的实现(软编码)
Linux摄像头驱动学习之:(一)V4L2_框架分析
Linux摄像头驱动学习之:(二)通过虚拟驱动vivi分析摄像头驱动
五、busybox
bootloader与linux中位置无关代码(PIC)的分析理解