Linux内核裁剪与配置:从零开始定制你的嵌入式内核¶

Linux内核裁剪与配置:从零开始定制你的嵌入式内核¶

Linux内核裁剪与配置:从零开始定制你的嵌入式内核¶

学习目标¶

完成本教程后,你将能够:

理解Linux内核配置系统的工作原理

熟练使用menuconfig进行内核配置

掌握内核功能裁剪的策略和方法

独立完成内核的编译和安装

配置和测试定制内核的启动

解决常见的内核配置和编译问题

优化内核大小和性能

前置要求¶

在开始学习之前,建议你具备:

知识要求:

- 了解Linux基本操作和命令行

- 理解嵌入式Linux系统架构

- 熟悉C语言编程

- 了解交叉编译的概念

技能要求:

- 能够使用Linux命令行工具

- 会使用文本编辑器(vi/nano)

- 了解Makefile基础

- 熟悉基本的硬件知识

硬件和软件准备:

- Linux开发主机(Ubuntu 20.04+推荐)

- 目标开发板或QEMU模拟器

- 交叉编译工具链

- 至少20GB可用磁盘空间

- 4GB以上内存

实验环境准备¶

1. 开发主机配置¶

安装必要的软件包:

# 更新软件包列表

sudo apt update

# 安装编译工具

sudo apt install -y build-essential gcc g++ make

# 安装内核编译依赖

sudo apt install -y libncurses5-dev libssl-dev

sudo apt install -y bison flex libelf-dev

# 安装其他工具

sudo apt install -y bc u-boot-tools device-tree-compiler

sudo apt install -y git wget curl

# 安装交叉编译工具链(以ARM为例)

sudo apt install -y gcc-arm-linux-gnueabihf

sudo apt install -y g++-arm-linux-gnueabihf

2. 创建工作目录¶

# 创建工作目录

mkdir -p ~/embedded-linux/kernel

cd ~/embedded-linux/kernel

# 设置环境变量

export WORK_DIR=~/embedded-linux/kernel

export ARCH=arm

export CROSS_COMPILE=arm-linux-gnueabihf-

3. 下载Linux内核源码¶

方法一:从官方网站下载

# 下载稳定版内核(以5.15 LTS为例)

cd $WORK_DIR

wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.tar.xz

# 解压

tar -xf linux-5.15.tar.xz

cd linux-5.15

方法二:使用Git克隆

# 克隆内核仓库(推荐用于开发)

cd $WORK_DIR

git clone --depth=1 --branch v5.15 \

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git linux-5.15

cd linux-5.15

方法三:使用国内镜像(加速)

# 使用清华大学镜像

wget https://mirrors.tuna.tsinghua.edu.cn/kernel/v5.x/linux-5.15.tar.xz

# 或使用中科大镜像

wget https://mirrors.ustc.edu.cn/kernel.org/linux/kernel/v5.x/linux-5.15.tar.xz

Linux内核配置系统详解¶

配置系统架构¶

Linux内核使用Kconfig语言定义配置选项,配置系统包含三个核心组件:

┌─────────────────────────────────────────┐

│ Kconfig文件 │

│ 定义配置选项和依赖关系 │

└─────────────────────────────────────────┘

┌─────────────────────────────────────────┐

│ 配置工具(menuconfig等) │

│ 用户界面,生成.config文件 │

└─────────────────────────────────────────┘

┌─────────────────────────────────────────┐

│ .config文件 │

│ 存储用户的配置选择 │

└─────────────────────────────────────────┘

┌─────────────────────────────────────────┐

│ Makefile系统 │

│ 根据.config编译内核 │

└─────────────────────────────────────────┘

配置选项类型¶

1. bool类型

- 只有两个值:y(编译进内核)或n(不编译)

- 示例:CONFIG_SMP=y

2. tristate类型

- 三个值:y(编译进内核)、m(编译为模块)、n(不编译)

- 示例:CONFIG_EXT4_FS=m

3. string类型

- 字符串值

- 示例:CONFIG_LOCALVERSION="-custom"

4. int/hex类型

- 整数或十六进制值

- 示例:CONFIG_HZ=100

配置文件说明¶

主要配置文件:

文件

说明

.config

当前内核配置(生成的)

defconfig

默认配置模板

arch/*/configs/*_defconfig

架构特定的默认配置

Kconfig

配置选项定义

.config.old

配置备份

内核配置工具详解¶

1. menuconfig(推荐)¶

特点:

- 基于ncurses的文本界面

- 最常用的配置工具

- 支持搜索和帮助功能

- 适合远程SSH操作

启动menuconfig:

cd $WORK_DIR/linux-5.15

# 本地编译

make menuconfig

# 交叉编译(ARM)

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig

界面说明:

┌─────────────────────────────────────────────────────────┐

│ Linux/arm 5.15.0 Kernel Configuration │

├─────────────────────────────────────────────────────────┤

│ Arrow keys navigate the menu. │

selects submenus --->. │

│ Highlighted letters are hotkeys. │

│ Pressing includes, excludes, modularizes │

│ Press to exit, for Help, for Search │

├─────────────────────────────────────────────────────────┤

│ [ ] 64-bit kernel │

│ General setup ---> │

│ [*] Enable loadable module support ---> │

│ [*] Enable the block layer ---> │

│ Processor type and features ---> │

│ Power management and ACPI options ---> │

│ Bus options (PCI etc.) ---> │

│ Kernel hacking ---> │

│ Security options ---> │

│ Cryptographic API ---> │

│ Library routines ---> │

└─────────────────────────────────────────────────────────┘

操作快捷键:

按键

功能

↑↓

上下移动

←→

左右切换底部选项

Enter

进入子菜单

Esc Esc

返回上级或退出

Y

选中(编译进内核)

N

不选中

M

编译为模块

?

显示帮助信息

/

搜索配置项

Space

切换选项状态

搜索功能:

# 在menuconfig中按 / 键

# 输入搜索关键字,如:EXT4

搜索结果示例:

Symbol: EXT4_FS [=m]

Type : tristate

Prompt: The Extended 4 (ext4) filesystem

Location:

-> File systems

-> Ext4 filesystem support (EXT4_FS [=m])

Defined at fs/ext4/Kconfig:1

Depends on: BLOCK [=y]

2. xconfig(图形界面)¶

特点:

- 基于Qt的图形界面

- 功能强大,界面友好

- 需要X Window支持

- 适合本地开发

启动xconfig:

# 需要安装Qt开发库

sudo apt install -y qt5-default

# 启动xconfig

make ARCH=arm xconfig

3. gconfig(GTK图形界面)¶

特点:

- 基于GTK+的图形界面

- 轻量级图形工具

- 需要GTK+支持

启动gconfig:

# 安装GTK+开发库

sudo apt install -y libglade2-dev

# 启动gconfig

make ARCH=arm gconfig

4. oldconfig(命令行)¶

特点:

- 基于现有配置更新

- 只询问新增的配置项

- 适合内核版本升级

使用方法:

# 使用旧配置,只询问新选项

make ARCH=arm oldconfig

# 使用旧配置,新选项使用默认值

make ARCH=arm olddefconfig

5. defconfig(默认配置)¶

特点:

- 使用架构默认配置

- 快速生成基础配置

- 适合初次配置

使用方法:

# 查看可用的defconfig

ls arch/arm/configs/

# 使用特定的defconfig

make ARCH=arm vexpress_defconfig

# 常用的ARM defconfig

make ARCH=arm multi_v7_defconfig # 多平台支持

make ARCH=arm imx_v6_v7_defconfig # i.MX6/7平台

内核配置实战¶

实战一:基础配置流程¶

步骤1:选择基础配置

cd $WORK_DIR/linux-5.15

# 使用多平台默认配置

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- multi_v7_defconfig

# 查看生成的.config文件

ls -lh .config

步骤2:启动menuconfig

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig

步骤3:配置基本选项

1. General setup

- 设置内核版本后缀

- 配置初始化系统

- 设置默认主机名

2. System Type

- 选择处理器类型

- 配置板级支持

3. Kernel Features

- 配置内存管理

- 设置定时器频率

- 配置抢占模式

步骤4:保存配置

- 按 Esc Esc 退出

- 选择 Yes 保存配置

- 配置保存到 .config 文件

实战二:定制内核版本信息¶

配置路径:

General setup

-> Local version - append to kernel release

配置示例:

# 在menuconfig中设置

CONFIG_LOCALVERSION="-myboard-v1.0"

# 或直接编辑.config

echo 'CONFIG_LOCALVERSION="-myboard-v1.0"' >> .config

验证:

# 编译后查看版本

make ARCH=arm kernelversion

# 输出:5.15.0-myboard-v1.0

实战三:配置文件系统支持¶

常用文件系统配置:

File systems --->

[*] Second extended fs support (EXT2)

The Extended 4 (ext4) filesystem

[*] Ext4 POSIX Access Control Lists

[*] Ext4 Security Labels

DOS/FAT/NT Filesystems --->

MSDOS fs support

VFAT (Windows-95) fs support

(437) Default codepage for FAT

(utf8) Default iocharset for FAT

Pseudo filesystems --->

[*] /proc file system support

[*] sysfs file system support

[*] Tmpfs virtual memory file system support

[*] Tmpfs POSIX Access Control Lists

配置说明:

文件系统

用途

建议

ext4

Linux标准文件系统

必选

ext2

简单文件系统

可选

FAT/VFAT

Windows兼容

SD卡必选

tmpfs

内存文件系统

必选

proc

进程信息

必选

sysfs

设备信息

必选

实战四:配置网络支持¶

基础网络配置:

[*] Networking support --->

Networking options --->

<*> Packet socket

<*> Unix domain sockets

[*] TCP/IP networking

[*] IP: multicasting

[*] IP: advanced router

[*] IP: kernel level autoconfiguration

[*] IP: DHCP support

[*] IP: BOOTP support

网络设备驱动:

Device Drivers --->

[*] Network device support --->

[*] Ethernet driver support --->

[*] Intel devices

Intel(R) PRO/1000 Gigabit Ethernet support

[*] Realtek devices

RealTek RTL-8139 C+ PCI Fast Ethernet Adapter

实战五:配置USB支持¶

USB主机控制器:

Device Drivers --->

[*] USB support --->

<*> Support for Host-side USB

<*> EHCI HCD (USB 2.0) support

<*> OHCI HCD (USB 1.1) support

<*> USB Mass Storage support

<*> USB Serial Converter support --->

USB FTDI Single Port Serial Driver

USB设备类驱动:

Device Drivers --->

[*] USB support --->

<*> USB Mass Storage support

<*> USB Human Interface Device (HID) support

USB Keyboard support

USB Mouse support

内核功能裁剪策略¶

裁剪原则¶

1. 明确需求

- 确定目标硬件平台

- 列出必需的功能

- 识别可选的功能

- 考虑未来扩展

2. 分层裁剪

- 先裁剪大模块

- 再优化小功能

- 保留调试功能(开发阶段)

- 最后优化大小

3. 测试验证

- 每次裁剪后测试

- 记录配置变更

- 保留配置备份

- 验证功能完整性

裁剪策略详解¶

策略一:移除不需要的架构支持

Processor type and features --->

[ ] Symmetric multi-processing support # 单核系统不需要

[ ] Support for extended (non-PC) x86 platforms # 嵌入式不需要

策略二:精简文件系统

# 只保留必需的文件系统

File systems --->

# 移除不用的文件系统

< > Btrfs filesystem support

< > XFS filesystem support

< > JFS filesystem support

< > ReiserFS support

# 保留必需的

<*> The Extended 4 (ext4) filesystem

<*> Tmpfs virtual memory file system support

策略三:移除不需要的驱动

Device Drivers --->

# 移除不用的总线支持

[ ] PCI support # 如果没有PCI设备

# 移除不用的图形支持

Graphics support --->

< > Direct Rendering Manager # 无图形界面时

# 移除不用的声音支持

< > Sound card support # 无音频需求时

策略四:优化网络协议栈

[*] Networking support --->

Networking options --->

# 移除不用的协议

< > The IPv6 protocol # 如果只用IPv4

< > IPsec protocol # 不需要VPN时

< > Bluetooth subsystem support # 无蓝牙时

策略五:精简内核功能

General setup --->

[ ] Auditing support # 移除审计

[ ] Enable kernel .config support # 移除配置支持

Kernel hacking --->

# 生产环境移除调试功能

[ ] Kernel debugging

[ ] Debug filesystem

内核大小优化¶

优化技巧:

1. 使用模块化

# 将不常用功能编译为模块

而不是 <*>

# 优点:

- 减小内核镜像大小

- 按需加载功能

- 便于更新单个模块

# 缺点:

- 需要文件系统支持

- 启动时间略长

- 需要管理模块文件

2. 启用内核压缩

General setup --->

Kernel compression mode (XZ) --->

(X) XZ # 最高压缩比

( ) GZIP # 最快解压

( ) BZIP2 # 平衡选择

( ) LZMA # 高压缩比

( ) LZO # 快速解压

( ) LZ4 # 最快解压

压缩算法对比:

算法

压缩比

解压速度

适用场景

XZ

最高

存储受限

GZIP

中等

通用

BZIP2

中等

平衡

LZO

最快

启动速度优先

LZ4

极快

快速启动

3. 移除符号信息

# 编译时不包含调试符号

General setup --->

[ ] Compile the kernel with debug info

# 或使用strip命令

arm-linux-gnueabihf-strip vmlinux

4. 优化编译选项

# 使用-Os优化大小

General setup --->

Compiler optimization level (Optimize for size) --->

(X) Optimize for size

裁剪效果对比¶

典型配置大小对比:

配置类型

内核大小

模块大小

总大小

适用场景

完整配置

8-12 MB

50-100 MB

60-110 MB

开发调试

标准裁剪

4-6 MB

10-20 MB

15-25 MB

通用产品

深度裁剪

2-3 MB

5-10 MB

7-13 MB

资源受限

极限裁剪

1-2 MB

0-5 MB

1-7 MB

极度受限

裁剪示例:

# 查看当前内核大小

ls -lh arch/arm/boot/zImage

# 裁剪前:6.5 MB

# 裁剪后:2.8 MB

# 减少:57%

内核编译详解¶

编译准备¶

1. 清理旧的编译文件

# 清理编译生成的文件

make clean

# 深度清理(包括配置)

make mrproper

# 清理所有生成文件(包括备份)

make distclean

2. 设置编译参数

# 设置环境变量

export ARCH=arm

export CROSS_COMPILE=arm-linux-gnueabihf-

# 或在make命令中指定

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-

3. 检查配置

# 查看当前配置

make ARCH=arm listnewconfig

# 检查配置依赖

scripts/diffconfig .config.old .config

编译内核¶

基本编译命令:

# 编译内核镜像

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j$(nproc)

# 参数说明:

# -j$(nproc):使用所有CPU核心并行编译

# -j4:使用4个核心编译

编译输出:

编译过程输出示例:

CC init/main.o

CC init/version.o

CC init/do_mounts.o

LD init/built-in.o

...

OBJCOPY arch/arm/boot/Image

Kernel: arch/arm/boot/Image is ready

GZIP arch/arm/boot/compressed/piggy.gzip

AS arch/arm/boot/compressed/piggy.gzip.o

LD arch/arm/boot/compressed/vmlinux

OBJCOPY arch/arm/boot/zImage

Kernel: arch/arm/boot/zImage is ready

编译目标说明:

目标

说明

文件位置

vmlinux

未压缩的内核ELF文件

vmlinux

Image

未压缩的二进制内核

arch/arm/boot/Image

zImage

压缩的内核镜像

arch/arm/boot/zImage

uImage

U-Boot格式镜像

arch/arm/boot/uImage

modules

内核模块

*.ko

dtbs

设备树二进制

arch/arm/boot/dts/*.dtb

编译特定目标¶

1. 只编译内核镜像

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage -j$(nproc)

2. 编译内核模块

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules -j$(nproc)

3. 编译设备树

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs -j$(nproc)

4. 编译U-Boot格式镜像

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- uImage \

LOADADDR=0x80008000 -j$(nproc)

5. 编译所有目标

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- \

zImage modules dtbs -j$(nproc)

安装内核和模块¶

1. 安装模块到指定目录

# 设置安装路径

export INSTALL_MOD_PATH=/path/to/rootfs

# 安装模块

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- \

modules_install INSTALL_MOD_PATH=$INSTALL_MOD_PATH

# 查看安装的模块

ls $INSTALL_MOD_PATH/lib/modules/

2. 复制内核镜像

# 复制zImage

cp arch/arm/boot/zImage /path/to/boot/

# 复制设备树

cp arch/arm/boot/dts/*.dtb /path/to/boot/

3. 生成System.map

# System.map包含内核符号表

cp System.map /path/to/boot/System.map-5.15.0

编译优化技巧¶

1. 使用ccache加速编译

# 安装ccache

sudo apt install ccache

# 配置ccache

export CC="ccache arm-linux-gnueabihf-gcc"

export CROSS_COMPILE="ccache arm-linux-gnueabihf-"

# 编译

make ARCH=arm -j$(nproc)

# 查看缓存统计

ccache -s

2. 使用distcc分布式编译

# 安装distcc

sudo apt install distcc

# 配置distcc

export DISTCC_HOSTS="localhost 192.168.1.100"

export CC="distcc arm-linux-gnueabihf-gcc"

# 编译

make ARCH=arm -j16

3. 只编译修改的部分

# 增量编译(只编译修改的文件)

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j$(nproc)

# 强制重新编译特定文件

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- \

drivers/net/ethernet/realtek/r8169.o

内核启动测试¶

使用QEMU测试¶

1. 安装QEMU

# 安装QEMU ARM模拟器

sudo apt install qemu-system-arm

2. 准备测试环境

# 创建简单的initramfs

mkdir -p initramfs/{bin,sbin,etc,proc,sys,dev}

cd initramfs

# 创建init脚本

cat > init << 'EOF'

#!/bin/sh

mount -t proc none /proc

mount -t sysfs none /sys

mount -t devtmpfs none /dev

echo "Welcome to Embedded Linux!"

echo "Kernel version: $(uname -r)"

exec /bin/sh

EOF

chmod +x init

# 创建initramfs镜像

find . | cpio -o -H newc | gzip > ../initramfs.cpio.gz

cd ..

3. 启动QEMU测试

# 使用QEMU启动内核

qemu-system-arm \

-M vexpress-a9 \

-m 512M \

-kernel arch/arm/boot/zImage \

-dtb arch/arm/boot/dts/vexpress-v2p-ca9.dtb \

-initrd initramfs.cpio.gz \

-append "console=ttyAMA0" \

-nographic

# 参数说明:

# -M:指定机器类型

# -m:内存大小

# -kernel:内核镜像

# -dtb:设备树

# -initrd:初始化内存盘

# -append:内核启动参数

# -nographic:不使用图形界面

4. 验证启动

启动成功输出示例:

Booting Linux on physical CPU 0x0

Linux version 5.15.0-custom (user@host) (gcc version 9.3.0)

CPU: ARMv7 Processor [410fc090] revision 0 (ARMv7), cr=10c5387d

...

Welcome to Embedded Linux!

Kernel version: 5.15.0-custom

/ #

在真实硬件上测试¶

1. 准备SD卡或Flash

# 分区SD卡

sudo fdisk /dev/sdX

# 创建分区:

# 分区1:FAT32,100MB,用于boot

# 分区2:ext4,剩余空间,用于rootfs

# 格式化分区

sudo mkfs.vfat -F 32 /dev/sdX1

sudo mkfs.ext4 /dev/sdX2

2. 安装内核和模块

# 挂载分区

sudo mount /dev/sdX1 /mnt/boot

sudo mount /dev/sdX2 /mnt/rootfs

# 复制内核

sudo cp arch/arm/boot/zImage /mnt/boot/

sudo cp arch/arm/boot/dts/*.dtb /mnt/boot/

# 安装模块

sudo make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- \

modules_install INSTALL_MOD_PATH=/mnt/rootfs

# 卸载分区

sudo umount /mnt/boot

sudo umount /mnt/rootfs

3. 配置U-Boot启动参数

# 在U-Boot命令行中设置

setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk0p2 rootwait rw'

setenv bootcmd 'fatload mmc 0:1 0x80800000 zImage; fatload mmc 0:1 0x83000000 imx6ull-14x14-evk.dtb; bootz 0x80800000 - 0x83000000'

saveenv

# 启动

boot

4. 监控启动过程

# 通过串口查看启动日志

sudo minicom -D /dev/ttyUSB0 -b 115200

# 或使用screen

sudo screen /dev/ttyUSB0 115200

启动参数详解¶

常用内核启动参数:

参数

说明

示例

console

控制台设备

console=ttyS0,115200

root

根文件系统设备

root=/dev/mmcblk0p2

rootfstype

根文件系统类型

rootfstype=ext4

rootwait

等待根设备就绪

rootwait

rw

读写挂载根文件系统

rw

ro

只读挂载根文件系统

ro

init

指定init程序

init=/sbin/init

ip

网络配置

ip=dhcp

mem

内存大小

mem=512M

quiet

减少启动信息

quiet

debug

启用调试信息

debug

完整启动参数示例:

# 标准配置

console=ttyS0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait rw

# 网络启动

console=ttyS0,115200 root=/dev/nfs nfsroot=192.168.1.100:/nfs/rootfs ip=dhcp

# 调试模式

console=ttyS0,115200 root=/dev/mmcblk0p2 rootwait rw debug loglevel=8

常见问题与解决方案¶

问题1:编译错误¶

错误:缺少头文件

错误信息:

fatal error: openssl/opensslv.h: No such file or directory

解决方案:

sudo apt install libssl-dev

错误:缺少ncurses库

错误信息:

Unable to find the ncurses libraries

解决方案:

sudo apt install libncurses5-dev

错误:交叉编译工具链未找到

错误信息:

arm-linux-gnueabihf-gcc: command not found

解决方案:

# 安装交叉编译工具链

sudo apt install gcc-arm-linux-gnueabihf

# 或设置正确的PATH

export PATH=/path/to/toolchain/bin:$PATH

问题2:配置错误¶

错误:配置选项冲突

问题:

某些选项无法同时启用

解决方案:

# 使用搜索功能查看依赖

在menuconfig中按 / 搜索选项

查看 Depends on 和 Selects 信息

错误:配置丢失

问题:

.config文件被删除或损坏

解决方案:

# 从备份恢复

cp .config.old .config

# 或重新生成

make ARCH=arm defconfig

问题3:启动失败¶

问题:内核panic

错误信息:

Kernel panic - not syncing: VFS: Unable to mount root fs

原因分析:

1. 根文件系统设备路径错误

2. 根文件系统类型不支持

3. 根文件系统损坏

解决方案:

# 检查启动参数

root=/dev/mmcblk0p2 # 确认设备路径正确

# 确保文件系统支持已编译

CONFIG_EXT4_FS=y

# 检查文件系统

sudo fsck.ext4 /dev/sdX2

问题:无法找到init

错误信息:

Kernel panic - not syncing: No working init found

原因分析:

1. init程序不存在

2. init程序权限错误

3. init程序依赖库缺失

解决方案:

# 检查init程序

ls -l /sbin/init

# 确保可执行权限

chmod +x /sbin/init

# 检查依赖库

arm-linux-gnueabihf-readelf -d /sbin/init

问题:串口无输出

原因分析:

1. 串口设备配置错误

2. 波特率不匹配

3. 串口驱动未启用

解决方案:

# 检查启动参数

console=ttyS0,115200 # 确认设备和波特率

# 确保串口驱动已启用

Device Drivers --->

Character devices --->

[*] Serial drivers --->

<*> 8250/16550 and compatible serial support

问题4:性能问题¶

问题:启动时间过长

分析方法:

# 使用内核启动时间分析

在启动参数中添加:

initcall_debug

# 查看启动日志

dmesg | grep "initcall"

优化方案:

1. 移除不必要的驱动

2. 使用异步初始化

3. 优化文件系统

4. 减少模块数量

问题:内存占用过高

分析方法:

# 查看内存使用

cat /proc/meminfo

free -h

# 查看内核内存使用

cat /proc/slabinfo

优化方案:

1. 裁剪不必要的功能

2. 使用轻量级C库

3. 减少内核缓存

4. 优化模块加载

问题5:模块加载失败¶

问题:模块版本不匹配

错误信息:

insmod: ERROR: could not insert module: Invalid module format

原因:

内核版本与模块版本不匹配

解决方案:

# 重新编译模块

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules

# 重新安装模块

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- \

modules_install INSTALL_MOD_PATH=/path/to/rootfs

问题:找不到模块依赖

错误信息:

modprobe: FATAL: Module xxx not found

解决方案:

# 更新模块依赖

depmod -a

# 或在目标系统上

depmod -a 5.15.0-custom

高级配置技巧¶

1. 内核配置片段¶

创建配置片段:

# 创建配置片段文件

cat > my-config.fragment << EOF

CONFIG_LOCALVERSION="-myboard"

CONFIG_EXT4_FS=y

CONFIG_USB_STORAGE=m

EOF

# 合并配置片段

scripts/kconfig/merge_config.sh \

arch/arm/configs/multi_v7_defconfig \

my-config.fragment

使用场景:

- 团队共享配置

- 版本控制配置变更

- 快速应用配置修改

- 自动化构建

2. 配置差异分析¶

# 比较两个配置文件

scripts/diffconfig .config.old .config

# 输出示例:

+CONFIG_EXT4_FS y -> m

-CONFIG_BTRFS_FS y

+CONFIG_USB_STORAGE m

3. 配置验证¶

# 检查配置完整性

make ARCH=arm olddefconfig

# 列出新增的配置项

make ARCH=arm listnewconfig

# 检查未设置的配置

scripts/checkconfig.pl .config

4. 自动化配置脚本¶

#!/bin/bash

# auto-config.sh - 自动化内核配置脚本

set -e

ARCH=arm

CROSS_COMPILE=arm-linux-gnueabihf-

DEFCONFIG=multi_v7_defconfig

# 生成基础配置

make ARCH=$ARCH $DEFCONFIG

# 应用自定义配置

scripts/config --enable EXT4_FS

scripts/config --module USB_STORAGE

scripts/config --disable DEBUG_INFO

scripts/config --set-str LOCALVERSION "-custom"

# 更新配置

make ARCH=$ARCH olddefconfig

# 显示关键配置

echo "Key configurations:"

scripts/config --state EXT4_FS

scripts/config --state USB_STORAGE

echo "Configuration completed!"

实战项目:为树莓派定制内核¶

项目目标¶

为树莓派4B定制一个精简的Linux内核,包含:

- 基本系统功能

- GPIO支持

- I2C/SPI支持

- USB和网络支持

- 优化启动时间和内存占用

步骤1:准备环境¶

# 创建工作目录

mkdir -p ~/rpi-kernel

cd ~/rpi-kernel

# 下载树莓派内核源码

git clone --depth=1 --branch rpi-5.15.y \

https://github.com/raspberrypi/linux.git

cd linux

# 安装交叉编译工具链

sudo apt install gcc-arm-linux-gnueabihf \

gcc-aarch64-linux-gnu

步骤2:基础配置¶

# 设置环境变量(64位)

export ARCH=arm64

export CROSS_COMPILE=aarch64-linux-gnu-

export KERNEL=kernel8

# 使用树莓派默认配置

make bcm2711_defconfig

步骤3:定制配置¶

# 启动menuconfig

make menuconfig

# 进行以下配置:

# 1. 设置版本信息

General setup --->

(-rpi4-custom-v1.0) Local version

# 2. 启用GPIO支持

Device Drivers --->

[*] GPIO Support --->

<*> /sys/class/gpio/... (sysfs interface)

<*> Broadcom BCM2835 GPIO

# 3. 启用I2C支持

Device Drivers --->

I2C support --->

<*> I2C device interface

<*> Broadcom BCM2835 I2C controller

# 4. 启用SPI支持

Device Drivers --->

[*] SPI support --->

<*> BCM2835 SPI controller

<*> User mode SPI device driver support

# 5. 优化内存

General setup --->

Kernel compression mode (XZ) --->

Compiler optimization level (Optimize for size) --->

# 6. 移除不需要的功能

[ ] Auditing support

[ ] Enable kernel .config support

步骤4:编译内核¶

# 编译内核、模块和设备树

make -j$(nproc) Image modules dtbs

# 编译时间:约15-30分钟(取决于CPU性能)

步骤5:安装到SD卡¶

# 挂载SD卡分区

sudo mount /dev/sdX1 /mnt/boot

sudo mount /dev/sdX2 /mnt/rootfs

# 安装内核

sudo cp arch/arm64/boot/Image /mnt/boot/kernel8.img

# 安装设备树

sudo cp arch/arm64/boot/dts/broadcom/*.dtb /mnt/boot/

sudo cp arch/arm64/boot/dts/overlays/*.dtb* /mnt/boot/overlays/

# 安装模块

sudo make modules_install INSTALL_MOD_PATH=/mnt/rootfs

# 卸载分区

sudo umount /mnt/boot

sudo umount /mnt/rootfs

步骤6:测试启动¶

# 插入SD卡到树莓派

# 连接串口或HDMI

# 上电启动

# 验证内核版本

uname -r

# 输出:5.15.0-rpi4-custom-v1.0

# 测试GPIO

echo 18 > /sys/class/gpio/export

echo out > /sys/class/gpio/gpio18/direction

echo 1 > /sys/class/gpio/gpio18/value

# 测试I2C

i2cdetect -y 1

# 测试SPI

ls /dev/spidev*

步骤7:性能优化¶

# 测量启动时间

systemd-analyze

# 查看内存使用

free -h

# 优化结果:

# - 启动时间:从15秒优化到8秒

# - 内存占用:从200MB优化到120MB

# - 内核大小:从8MB优化到4.5MB

内核配置最佳实践¶

1. 配置管理¶

版本控制:

# 将配置文件加入版本控制

git add .config

git commit -m "Add kernel configuration for board X"

# 使用配置片段

git add configs/board-x.fragment

配置文档化:

# 创建配置说明文档

cat > CONFIG.md << EOF

# Kernel Configuration for Board X

## Base Configuration

- Defconfig: multi_v7_defconfig

- Kernel Version: 5.15.0

## Custom Options

- CONFIG_LOCALVERSION="-boardx"

- CONFIG_EXT4_FS=y

- CONFIG_USB_STORAGE=m

## Disabled Features

- CONFIG_DEBUG_INFO=n

- CONFIG_BTRFS_FS=n

## Build Instructions

\`\`\`bash

make ARCH=arm multi_v7_defconfig

scripts/kconfig/merge_config.sh .config configs/boardx.fragment

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j$(nproc)

\`\`\`

EOF

2. 测试策略¶

分阶段测试:

# 阶段1:基础功能测试

- 内核启动

- 串口输出

- 根文件系统挂载

# 阶段2:驱动功能测试

- GPIO操作

- I2C通信

- SPI通信

- 网络连接

# 阶段3:性能测试

- 启动时间

- 内存占用

- CPU使用率

- 网络吞吐量

# 阶段4:稳定性测试

- 长时间运行

- 压力测试

- 异常恢复

自动化测试脚本:

#!/bin/bash

# kernel-test.sh - 内核功能测试脚本

echo "=== Kernel Test Suite ==="

# 测试1:内核版本

echo "Test 1: Kernel Version"

uname -r

# 测试2:文件系统

echo "Test 2: Filesystem Support"

cat /proc/filesystems

# 测试3:网络

echo "Test 3: Network Interface"

ip link show

# 测试4:USB

echo "Test 4: USB Devices"

lsusb

# 测试5:内存

echo "Test 5: Memory Info"

free -h

# 测试6:模块

echo "Test 6: Loaded Modules"

lsmod | head -10

echo "=== Test Complete ==="

3. 性能优化¶

启动时间优化:

# 1. 使用快速压缩算法

General setup --->

Kernel compression mode (LZ4) --->

# 2. 减少驱动初始化时间

Device Drivers --->

# 将不必要的驱动编译为模块

而不是 <*>

# 3. 优化文件系统

File systems --->

# 只保留必需的文件系统

<*> The Extended 4 (ext4) filesystem

内存优化:

# 1. 使用轻量级选项

General setup --->

Compiler optimization level (Optimize for size) --->

# 2. 减少内核缓存

# 在启动参数中添加:

vm.min_free_kbytes=8192

vm.swappiness=10

# 3. 禁用不必要的功能

Kernel hacking --->

[ ] Kernel debugging

[ ] Debug filesystem

4. 安全加固¶

安全配置:

# 1. 启用安全特性

General setup --->

[*] Auditing support

[*] Enable different security models

Security options --->

[*] Enable access key retention support

[*] Socket and Networking Security Hooks

[*] NSA SELinux Support

# 2. 内核加固

Kernel hacking --->

[*] Kernel debugging

[*] Debug Filesystem

[ ] Compile the kernel with debug info # 生产环境禁用

安全启动参数:

# 添加安全相关的启动参数

security=selinux selinux=1 enforcing=1

总结¶

通过本教程,你应该已经掌握了:

✅ Linux内核配置系统的工作原理

✅ menuconfig等配置工具的使用方法

✅ 内核功能裁剪的策略和技巧

✅ 内核编译的完整流程

✅ 内核启动测试的方法

✅ 常见问题的诊断和解决

✅ 内核配置的最佳实践

关键要点¶

配置系统理解

Kconfig定义配置选项

.config存储配置结果

Makefile根据配置编译

工具选择

menuconfig:最常用,功能完善

defconfig:快速生成基础配置

oldconfig:版本升级时使用

裁剪策略

明确需求,分层裁剪

保留必需功能

测试验证每次修改

编译优化

使用并行编译(-j)

启用ccache加速

增量编译节省时间

测试验证

先用QEMU测试

再在真实硬件测试

分阶段验证功能

学习建议¶

对于初学者:

1. 从默认配置开始

2. 逐步了解各个配置选项

3. 多使用搜索和帮助功能

4. 记录每次配置的变更

5. 保持配置备份

对于进阶开发者:

1. 深入理解Kconfig语法

2. 学习编写配置片段

3. 掌握自动化配置方法

4. 优化编译和启动性能

5. 建立配置管理流程

对于团队开发:

1. 统一配置管理方式

2. 使用版本控制

3. 文档化配置决策

4. 建立测试流程

5. 定期审查和优化

下一步学习¶

建议按以下顺序继续学习:

1. 设备树配置¶

设备树(Device Tree)详解

学习设备树语法

理解设备树与驱动的关系

编写自定义设备树

2. 驱动开发¶

Linux驱动开发入门

学习驱动框架

开发字符设备驱动

调试驱动程序

3. 根文件系统¶

文件系统与根文件系统制作

制作根文件系统

配置系统服务

优化系统大小

4. 系统集成¶

嵌入式Linux完整系统构建

集成Bootloader、内核、根文件系统

完整系统测试

产品化部署

参考资料¶

官方文档¶

Linux内核文档

https://www.kernel.org/doc/html/latest/

内核配置文档

Kconfig语言参考

内核配置指南

Documentation/kbuild/kconfig-language.rst

Documentation/admin-guide/kernel-parameters.txt

架构特定文档

Documentation/arm/

Documentation/devicetree/

推荐书籍¶

《Linux内核配置与编译》

详细的配置说明

实战案例

《嵌入式Linux系统开发》

系统化的开发流程

配置优化技巧

《Linux设备驱动程序》

驱动与内核配置的关系

配置选项详解

在线资源¶

Bootlin培训材料

https://bootlin.com/docs/

免费的内核配置教程

eLinux.org

https://elinux.org/Kernel_Configuration

内核配置Wiki

Linux内核邮件列表

https://lkml.org/

配置相关讨论

工具和脚本¶

内核配置工具

menuconfig

xconfig

gconfig

配置脚本

scripts/config

scripts/diffconfig

scripts/kconfig/merge_config.sh

分析工具

bloat-o-meter:分析内核大小变化

checkpatch.pl:代码风格检查

get_maintainer.pl:查找维护者

常见问题解答¶

Q1: 如何选择合适的defconfig?¶

A: 根据目标平台选择:

ARM平台:

- multi_v7_defconfig:支持多个ARMv7平台

- imx_v6_v7_defconfig:i.MX6/7系列

- sunxi_defconfig:全志系列

- bcm2711_defconfig:树莓派4

查看可用配置:

ls arch/arm/configs/

选择建议:

- 优先使用厂商提供的defconfig

- 其次使用通用的multi_v7_defconfig

- 最后基于相似平台的defconfig修改

Q2: 内核配置后无法启动怎么办?¶

A: 按以下步骤排查:

检查启动参数

# 确认console、root等参数正确

console=ttyS0,115200 root=/dev/mmcblk0p2

启用调试信息

# 添加调试参数

debug loglevel=8 earlyprintk

检查必需配置

# 确保以下配置已启用

CONFIG_EXT4_FS=y # 根文件系统支持

CONFIG_DEVTMPFS=y # 设备文件系统

CONFIG_PROC_FS=y # proc文件系统

使用已知好的配置

# 从备份恢复

cp .config.old .config

Q3: 如何减小内核大小?¶

A: 多种优化方法:

1. 编译优化

General setup --->

Compiler optimization level (Optimize for size) --->

Kernel compression mode (XZ) --->

2. 功能裁剪

# 移除不需要的功能

[ ] Auditing support

[ ] Enable kernel .config support

[ ] Kernel debugging

3. 模块化

# 将不常用功能编译为模块

而不是 <*>

4. 移除符号

[ ] Compile the kernel with debug info

效果对比:

- 优化前:8MB

- 优化后:2-3MB

- 减少:60-70%

Q4: 如何加快编译速度?¶

A: 多种加速方法:

1. 并行编译

make -j$(nproc) # 使用所有CPU核心

2. 使用ccache

sudo apt install ccache

export CC="ccache gcc"

make -j$(nproc)

3. 增量编译

# 只编译修改的部分

make -j$(nproc)

4. 使用更快的文件系统

# 在tmpfs上编译

sudo mount -t tmpfs -o size=10G tmpfs /tmp/build

效果对比:

- 首次编译:30分钟

- 使用ccache后:5分钟

- 增量编译:1-2分钟

Q5: 如何管理多个内核配置?¶

A: 使用配置管理策略:

方法1:使用配置片段

# 创建基础配置

make multi_v7_defconfig

# 应用项目特定配置

scripts/kconfig/merge_config.sh \

.config \

configs/project-a.fragment

方法2:使用不同的配置文件

# 保存当前配置

cp .config configs/board-a.config

# 切换配置

cp configs/board-b.config .config

方法3:使用环境变量

# 指定配置文件

make KCONFIG_CONFIG=configs/board-a.config menuconfig

反馈与支持:

如果你在学习过程中遇到问题:

- 💬 在评论区留言讨论

- 📧 发送邮件到:support@embedded-platform.com

- 🐛 报告问题:GitHub Issues

贡献内容:

欢迎提交改进建议和补充内容!

版权声明:本文采用 CC BY-SA 4.0 许可协议。

最后更新:2024-01-15

文档版本:1.0