1 嵌入式 Linux 基础知识与关键知识点
嵌入式 Linux 指在资源受限、形态固定的硬件上运行裁剪或完整的 Linux 内核与用户空间,典型场景包括工业控制、网通设备、车载、消费电子等。下面按「先宏观、后内核、再系统与工程」组织,并标出面试与实践中反复出现的关键点。
1.1 嵌入式 Linux 在系统栈中的位置
┌─────────────────────────────────────────┐ │ 应用层:业务逻辑、中间件、GUI(可选) │ ├─────────────────────────────────────────┤ │ 用户空间:C 库、glibc/musl、shell、守护进程 │ ├─────────────────────────────────────────┤ │ Linux 内核:调度、内存、驱动、网络栈… │ ├─────────────────────────────────────────┤ │ Bootloader:U-Boot / Barebox 等 │ ├─────────────────────────────────────────┤ │ SoC:CPU + 外设控制器 + BootROM │ └─────────────────────────────────────────┘关键认知:
「会写应用层 C/C++」≠「能做好嵌入式 Linux」。中间隔着交叉编译、启动链、根文件系统、驱动与设备树、内核配置、调试手段等一整层。
1.2 计算机体系结构(必读底座)
| 主题 | 关键知识点 | 实践意义 |
|------|-------------|----------|
|CPU 与 ISA| ARMv7/AArch32、ARMv8-A/AArch64、RISC-V 等指令集差异;Thumb/ AArch64 混编概念 | 选对工具链三元组arch-vendor-os-eabi|
|内存层次| 寄存器 → Cache(L1/L2)→ 主存(DDR)→ 外设寄存器映射到物理地址| 理解 DMA cache 一致性、对齐与性能 |
|MMU| 虚拟地址、页表、TLB;用户态/内核态地址空间 | 用户程序看到的地址 ≠ 物理地址;驱动里ioremap等 |
|总线| AXI/AHB/APB;PCIe(部分嵌入式 SoC) | 外设挂在哪条总线影响带宽与延迟 |
|中断| IRQ、FIQ(ARM)、GIC;上半部/下半部 | 实时性与响应;不能在中断上下文做阻塞 |
|异常级别(ARM)| EL0~EL3、TrustZone 概念(按需) | 安全启动、TEE 与普通过内核开发的分界 |
关键点:能解释「为什么驱动里不能直接解引用用户传来的指针」「DMA 前后为何要 flush/invalidate cache」。
1.3 Linux 内核基础(嵌入式最常碰到的子集)
1.3.1 进程与调度
进程、线程、task_struct;CFS 调度器基本概念。
上下文:进程上下文、中断上下文、软中断/tasklet/workqueue。
关键点:中断里不能睡眠;可能睡眠的代码要放在进程上下文或可阻塞的 workqueue。
1.3.2 内存管理
物理页、伙伴系统、slab/kmalloc、vmalloc。
mmap、缺页、copy_to_user / copy_from_user。
关键点:内核栈很小;大数组不要放栈上;理解 OOM 与内存水位。
1.3.3 同步与锁
spinlock、mutex、semaphore、rwlock;RCU(了解即可)。
关键点:spinlock 持有期间不可抢占(非 RT 内核上典型假设);死锁排查思路。
1.3.4 块设备与网络(栈边)
块层、MTD/NAND 与常规块设备的区别(见下文存储)。
sk_buff、netdevice;socket 与协议栈分层。
1.3.5 设备模型(sysfs / driver model)
bus_type、device、driver、class;probe/remove 与生命周期。
关键点:现代嵌入式 ARM 上设备树(DT)与platform_driver的匹配关系。
1.4 设备树(Device Tree)—— ARM 嵌入式核心
设备树用.dts/.dtsi描述硬件:CPU、内存、时钟、GPIO、I2C/SPI 上的器件等,编译为.dtb由内核在启动时解析。
| 概念 | 说明 |
|------|------|
|compatible| 驱动匹配字符串,如"vendor,model"|
|reg| 寄存器物理地址与长度 |
|interrupts| 中断号及触发方式(与 GIC/父节点相关) |
|phandle / 引用| 时钟、GPIO、复位线等通过句柄关联 |
| **status = “disabled”** | 节点默认关闭,板级 dts 可okay` 覆盖 |
关键点:
会读内核源码中的
Documentation/devicetree/bindings(或上游文档)核对属性是否合法。理解dtsi 分层:SoC 公版
.dtsi+ 板级.dts覆盖/追加节点。
1.5 Linux 设备驱动(入门到进阶路径)
1.5.1 字符设备
cdev、file_operations(open/read/write/ioctl/mmap/release)。主次设备号、devtmpfs 与
/dev节点。
1.5.2 平台与总线型驱动
platform_driver+ 设备树匹配。
I2C / SPI子系统:
i2c_client、spi_device、核心 API。
1.5.3 并发与阻塞
- 等待队列
wait_queue;非阻塞与poll;环形缓冲区与生产者消费者。
1.5.4 中断与下半部
request_irq、threaded IRQ;tasklet(逐渐少用)、workqueue。
1.5.5 内存与 DMA
dma_alloc_coherent/dma_map_single;Cache 一致性与dma_sync_*。
1.5.6 常见子系统(按项目选学)
GPIO / Pinctrl:管脚复用与电气属性。
Regulator:供电使能与时序。
Clock:时钟树、enable/disable、rate。
PWM、ADC(IIO)、RTC、Watchdog。
关键点:能独立写出一个最小字符设备 + sysfs 属性或GPIO 控制 LED的模块,并会insmod/dmesg调试。
1.6 启动流程(Boot Flow)
典型链(名称因芯片而异):
BootROM:固化在芯片,从 SPI NOR / eMMC 等加载下一阶段。
SPL / FSBL:极小程序,初始化 DDR、最小时钟。
U-Boot(或 Barebox):网络下载、环境变量、
bootcmd、加载zImage/Image + dtb + initramfs(可选)。Linux 内核:解压、设备初始化、挂载 rootfs。
init:BusyBox init、systemd 或自定义。
关键点:
bootargs/内核命令行:console=、root=、rootfstype=、mem=、quiet等。FIT image、A/B 分区升级(了解工业与车载常见需求)。
1.7 交叉开发与工具链
| 概念 | 说明 |
|------|------|
|Host / Target| 在 x86 PC 上编译,在 ARM 板上运行 |
|交叉编译器|aarch64-linux-gnu-gcc等;与目标libc(glibc/musl)、内核头版本要匹配 |
|sysroot| 目标根文件系统头文件与库的路径,供链接使用 |
|ABI| 调用约定、硬浮点hf、EABI;与内核、根文件系统一致|
关键点:能读懂工具链前缀与链接报错里缺哪个 .so,会用readelf、file、ldd(在目标板上)分析二进制。
1.8 根文件系统(rootfs)与初始化
目录结构:FHS 常识(
/bin、/sbin、/etc、/lib、/usr、/var、/proc、/sys、/dev)。C 库:glibc vs musl(体积、兼容性、许可证倾向)。
BusyBox:常用 Unix 命令的集合,适合小 rootfs。
init:PID 1 的职责;inittab或 systemd unit(若用 systemd)。
库依赖:动态链接时目标板需带齐
.so或使用静态链接权衡。
关键点:能用手工或Buildroot/Yocto打出能启动进 shell 的最小系统,并理解initramfs与真实 root 切换(若使用)。
1.9 构建系统(工程级必知)
| 系统 | 特点 | 适用 |
|------|------|------|
|Buildroot| Makefile/Kconfig,生成简单 rootfs+内核+U-Boot 配置,上手快 | 小到中型项目、快速出镜像 |
|Yocto / OpenEmbedded| 配方(recipe)、层(layer)、高度可复现 | 多产品变体、长期维护、大型团队 |
|厂商 BSP| 芯片商提供的整套 SDK | 先跑通再逐步替换/升级组件 |
关键点:理解defconfig、package 选择、post-build 脚本、许可证合规(见下文)。
1.10 存储与文件系统
| 介质 | 注意点 |
|------|--------|
|Raw NAND| 坏块、ECC、wear leveling;UBI/UBIFS或 JFFS2(老) |
|eMMC / SD| 块设备;常见ext4;注意掉电与fsync|
|SPI NOR| 只读或读写分区;常放 kernel/dtb/小 rootfs |
|分区与 GPT| 分区表、A/B slot |
关键点:理解只读 root + overlay或双分区回滚在量产中的价值。
1.11 调试手段(优先级从高到低建议掌握)
| 手段 | 用途 |
|------|------|
|串口 console| 最早期的内核 printk、shell |
|dmesg / loglevel| 驱动与内核子系统日志 |
|/proc /sys| 运行时状态、调参 |
|gdbserver + 交叉 gdb| 用户态单步 |
|ftrace / perf(按需)| 延迟与热点 |
|JTAG/SWD| 内核早期、裸机、死机分析(硬件依赖) |
|kgdb、kdump(进阶)| 内核崩溃与在线调试 |
关键点:会配置earlyprintk与正确的 console=tty波特率*,能省大量「黑屏」时间。
1.12 实时与确定性(按需深入)
标准 Linux 为尽力而为调度;硬实时常需MCU 侧或RTOS 协处理器。
PREEMPT_RT补丁:将部分不可抢占区缩短,改善延迟;需内核配置与验证。
关键点:用cyclictest等工具量化延迟,避免「感觉实时」。
1.13 网络与安全(现代产品常考)
TCP/IP 基础、socket、iptables/nftables(若做网关)。
SSH、证书、OTA 签名、安全启动(Secure Boot)链:ROM → SPL → U-Boot → Kernel 验签思路。
Capabilities、非 root 运行、最小权限。
CVE 与内核版本:长期维护 LTS 内核的选择。
1.14 许可证与合规(不可忽视)
GPL:内核模块与内核链接的衍生作品传播时的合规要求(简述:需能提供源码与构建说明,具体问法务)。
BusyBox、内核、U-Boot等许可证混用时的manifest与发布物检查。
1.15 推荐学习路径(可执行顺序)
Shell + Makefile + Git:能在命令行完成编辑、编译、版本管理。
计算机组成 + ARM 体系结构入门:MMU、异常、中断。
应用交叉编译:写 hello world,静态/动态链接各做一次,
readelf -h看懂 Machine。Buildroot 或厂商 BSP:跑通串口 shell,会改
bootargs、换内核 dtb。设备树:对照硬件原理图改一个 GPIO/LED 节点并验证。
字符设备驱动:内核模块 insmod,ioctl 或 sysfs 与用户态通信。
I2C/SPI 传感器类驱动(按硬件选)。
Yocto 或更深层内核子系统:按职业方向再分叉。
1.16 自检清单(「关键知识点」汇总)
用下面问题自测是否达到「初/中级嵌入式 Linux」常见要求:
说清从上电到 shell 提示符之间大致经过哪些软件阶段。
解释设备树里 compatible 与内核 probe如何对应。
说明中断上下文与进程上下文各能做什么、不能做什么。
配置并成功使用串口内核日志 + rootfs 挂载。
独立完成交叉编译并在目标板运行,解决常见动态库缺失。
使用Buildroot 或 Yocto之一生成过可启动镜像。
编写或修改过简单内核模块并理解许可证与导出符号。
了解NAND 与 eMMC在文件系统选型上的差异。
(选做)PREEMPT_RT或延迟测试的基本概念。
1.17 延伸阅读与权威来源
内核文档:内核源码树
Documentation/(设备树 bindings、驱动子系统)。Bootloader:U-Boot 官方文档(命令、FIT、DFU 等)。
书籍(经典向):Linux Device Drivers(LDD3 较老但思路仍有用)、Running Linux、体系结构侧ARM System Developer’s Guide类教材。
社区:kernel.org、各 SoC 厂商 wiki、ELinux.org。