嵌入式Linux内核编译与配置
目录
- 1. 嵌入式系统概述
- 2. 内核编译基础
- 2.1 解压内核源码包
- 2.2 关键文件说明
- 3. 内核配置与编译流程
- 3.1 拷贝默认配置
- 3.2 图形化配置
- 3.3 编译内核
- 4. 内核镜像类型说明
- 5. 向内核添加新驱动
- 5.1 编写源文件
- 5.2 修改Makefile
- 5.3 修改Kconfig
- 5.4 重新配置并编译
1. 嵌入式系统概述
嵌入式系统是一种软硬件可裁剪的专用计算机系统,通常用于特定应用场景(如智能设备、工控系统等)。与通用计算机系统不同,嵌入式系统通常资源有限,因此需要对其操作系统(如Linux)进行定制和剪裁。
2. 内核编译基础
a. 解压内核源码包
# 将内核源码包解压到Ubuntu系统中
tar -xzf linux-2.6.32.2-mini2440-20150709.tgz
b. 关键文件说明
xxx_defconfig
:默认配置文件,通常位于arch/arm/configs/
目录下。Kconfig
:定义make menuconfig
中可见的配置选项,每个子目录都有一个。会对我加入的参数做解释;.config
:保存make menuconfig
后的配置结果,决定哪些模块被编译进内核。Makefile
:根据.config
中的变量(如X1=y
)决定编译哪些文件。每一层目录都有对应的makefile
3. 内核配置与编译流程
以下指令均在linu顶层目录进行/linux2.6.32.2/
a. 拷贝默认配置
cp arch/arm/configs/config_mini2440_td35 .config
(隐藏文件需要ls -a才会出现)
b. 图形化配置
make menuconfig
- 通过菜单界面修改配置,结果保存在
.config
中。
注意!在make uImage之前出现bug把kernel下面的timeconst.pl文件夹第373行删掉
c. 编译内核
make uImage # 生成uImage内核镜像make modules # 编译模块
make # 编译全部(内核 + 模块)
上面图片这样就算编译成功 某某 is ready出现的时候
4. 内核镜像类型说明
这里出现异常:
这是ARM架构处理器运行程序时触发的未定义指令异常(Undefined Instruction Exception) ,属于硬件级错误,直接导致CPU复位。以下拆解关键信息和排查方向:
1. 核心错误:undefined instruction
- 含义:CPU执行到了不认识的指令编码。可能原因:
- 程序里有CPU不支持的指令集(比如用了ARMv7指令,却在ARMv5/ARM9内核运行 )。
- 内存数据被破坏,指令区被覆写成无效数据(比如栈溢出、指针错误)。
- 编译器配置错误(编译时选了错误的架构/指令集,导致生成的二进制指令不兼容 )。
2. 寄存器上下文解析(调试关键)
pc : [<3000801c>]
:pc
(程序计数器)是出错时正在执行的指令地址,可反汇编0x3000801c
附近代码,看具体指令:arm-linux-objdump -d 你的程序 | grep -C5 3000801c
lr : [<33f01200>]
:lr
(链接寄存器)保存函数调用返回地址,可辅助定位错误发生在哪个函数调用链。Mode SVC_32
:CPU处于32位管理模式(超级用户模式) ,说明错误发生在内核态或高权限代码(如果是用户程序触发,可能是非法指令触发了异常进入内核 )。
3. 典型排查方向
(1)指令集兼容性问题
- 检查编译工具链:确认用的是 ARM9 兼容的编译器(比如
arm-linux-gnueabi-gcc
针对ARMv5/ARM9 ),而非更高版本(如ARMv7、ARM64 )。 - 编译选项:确保
-march=armv5te
(或开发板CPU对应的架构)、-mtune=arm920t
等选项正确,避免生成不兼容指令。
(2)内存破坏/非法指针
- 检查栈溢出:递归过深、大数组局部变量可能撑爆栈(
sp
地址33affdd0
可结合栈大小判断)。 - 指针越界:确认
pc
指向的地址是否属于程序代码段(正常应在代码加载区间,若在数据区,可能是指针错误跳转到无效地址 )。
(3)内核/驱动兼容性
- 如果是加载内核模块或运行内核程序报错,检查内核配置:是否启用了不兼容的功能(比如内核用ARMv5编译,模块用ARMv7编译 )。
4. 总结:错误影响
- 直接触发CPU异常,导致程序崩溃,系统打印寄存器信息后执行
Resetting CPU ...
(复位CPU,重启或进入异常处理 )。 - 常见于嵌入式开发(如
mini2440
这类ARM9开发板 ),解决核心是对齐编译工具链、指令集、内存管理三者的兼容性 。
如果是自己编译程序/内核,优先从编译选项、指令集配置查起;如果是运行别人的程序,重点检查内存访问是否越界~
**
修改上面的错误往往要把arch/arm/boot里面的Makefile文件具体地址64行代码修改成 下面图片中正确格式,然后重新编译检查地址是否修改成功
然后编译结果是下面的
tftp 0x30008000 uImage
**
出现异常的时候,应该把地址修改成0x30008040像上面的图片一样修改成功才能是正确的编译文件
Image
:原始内核镜像,未经压缩。zImage
:压缩后的内核镜像,包含解压代码。uImage
:在zImage
前加64字节头信息,供U-Boot等引导程序使用
5. 向内核添加新驱动/文件(以 demo.c 为例)
a. 编写源文件
在 drivers/char/
下创建 demo.c
。
b. 修改 Makefile
在 drivers/char/Makefile
中添加:
obj-$(CONFIG_DOME) += demo.o //注意大小写
c. 修改 Kconfig
在 drivers/char/Kconfig
中添加配置选项:
config DEMObool "Hello driver support"default nhelpThis is a simple hello driver.
修改成功后进vi config检查demo.o文件是否存在
然后再图形化界面make menuconfig中查看详细地址-----这就是活地址的作用:(location后面就是相应的地址层,进入后再括号里面的*即是选择与否,可以通过空格键来选择与否,也可以通过y键和n键来确定)
d. 重新配置并编译
make menuconfig # 在菜单中启用 HELLO 选项
make uImage # 重新编译内核
最后去启动内核
tftp 0x30008000 uImage
bootm 0x30008000
如果结果中在TCP附近出现下面的带有#一行的信息则就是修改异常成功