一、系统启动流程(Boot Flow)
嵌入式 Linux 的启动流程是面试第一高频问题,核心链路如下:
ROM → Bootloader → Kernel → init → 用户空间
1. BootROM 阶段
- 固化在 SoC 内部(厂商提供)
- 完成最基本的硬件初始化(如 DDR 初始化的前置条件)
- 从指定介质加载 Bootloader(NAND / eMMC / SD)
2. Bootloader(如 U-Boot)
核心职责:
- 初始化 DDR、串口、时钟等外设
- 加载内核镜像(zImage / uImage / Image)
- 传递设备树(DTB)
- 设置启动参数(bootargs)
关键命令:
bootm/bootzsetenv bootargssaveenv
3. Kernel 启动
- 解压内核
- 建立页表
- 初始化中断系统
- 初始化驱动模型(platform / bus)
- 挂载根文件系统
4. init 进程
- 第一个用户态进程(PID = 1)
- 常见实现:busybox init / systemd
- 执行
/etc/inittab或 systemd unit
二、设备树(Device Tree)
设备树是嵌入式 Linux 的核心机制之一。
本质
用数据描述硬件,而不是在驱动中写死硬件信息。
文件结构
.dts:源文件.dtb:编译后
示例
uart0: serial@101f1000 {
compatible = "arm,pl011";
reg = <0x101f1000 0x1000>;
interrupts = <0 29 4>;
};
核心字段
compatible:驱动匹配关键reg:寄存器地址interrupts:中断号
匹配机制
驱动通过 of_match_table 匹配 compatible
全网最全面的嵌入式八股文专栏:https://www.nowcoder.com/creation/manager/columnDetail/mPZ4kk(涵盖大厂面试题和基础八股文)
三、Linux 驱动模型
Linux 设备驱动核心是 设备-驱动-总线模型。
三大核心结构
struct devicestruct driverstruct bus_type
匹配流程
- device 注册
- driver 注册
- bus 进行 match
- 调用
probe()
platform 设备
嵌入式中最常见:
static struct platform_driver xxx_driver = {
.probe = xxx_probe,
.remove = xxx_remove,
.driver = {
.name = "xxx",
.of_match_table = xxx_of_match,
},
};
四、字符设备驱动
核心步骤
- 申请设备号
- 初始化
cdev - 注册设备
- 实现 file_operations
关键结构
struct file_operations {
int (*open)(struct inode *, struct file *);
ssize_t (*read)(struct file *, char __user *, size_t, loff_t *);
ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *);
};
用户态访问
open() read() write() ioctl()
五、中断机制(Interrupt)
中断处理流程
- 硬件触发中断
- CPU 跳转中断向量表
- 执行 ISR(上半部)
- 调度下半部(tasklet / workqueue)
API
request_irq() free_irq()
上下半部
- 上半部:快速执行,不能睡眠
- 下半部:tasklet(软中断)workqueue(进程上下文)
六、进程与调度
进程状态
- TASK_RUNNING
- TASK_INTERRUPTIBLE
- TASK_UNINTERRUPTIBLE
调度策略
- CFS(完全公平调度)
- 实时调度:SCHED_FIFOSCHED_RR
上下文切换
- 保存寄存器
- 切换栈
- 切换 mm_struct
七、内存管理
虚拟内存
- 每个进程独立地址空间
- 用户态 / 内核态隔离
页表
- VA → PA 映射
分配方式
kmalloc(连续物理内存)vmalloc(虚拟连续)dma_alloc_coherent
内存分区
- ZONE_DMA
- ZONE_NORMAL
- ZONE_HIGHMEM
八、文件系统
常见类型
- ext4
- squashfs(只读)
- jffs2 / ubifs(Flash)
VFS(虚拟文件系统)
统一接口:
- inode
- file
- dentry
九、用户态与内核态通信
1. ioctl
ioctl(fd, CMD, arg);
2. mmap
- 用户态映射设备内存
3. netlink
- 内核与用户空间通信
4. sysfs
/sys文件系统- 设备属性
十、同步与并发
常见机制
- 自旋锁(spinlock)
- 互斥锁(mutex)
- 信号量(semaphore)
区别
spinlock | 否 |
mutex | 是 |
十一、调试手段
内核调试
printk- dmesg
- ftrace
常用工具
- strace
- gdb
- perf
十二、交叉编译
嵌入式开发必备:
工具链
- arm-linux-gcc
- aarch64-linux-gnu-gcc
关键点
- sysroot
- 依赖库路径
- ABI 匹配
十三、面试高频“灵魂拷问”
1. 为什么不能在中断里睡眠?
因为中断上下文没有进程调度能力。
2. kmalloc 和 vmalloc 区别?
- kmalloc:物理连续
- vmalloc:虚拟连续
3. 用户态如何访问驱动?
通过:
- 设备文件
/dev/xxx - 系统调用(open/read/write/ioctl)
4. probe 什么时候调用?
当 device 和 driver 匹配成功时。
总结
嵌入式 Linux 面试的本质是三点:
- 是否理解内核运行机制(而不是只会 API)
- 是否能把硬件和软件打通(设备树 + 驱动)
- 是否具备调试能力(定位问题能力)
真正的“硬核”,不是背八股,而是:
- 能解释“为什么这样设计”
- 能在异常情况下定位问题
- 能写出稳定的驱动代码
全部评论
(0) 回帖