2. 嵌入式Linux基础
在 Qualcomm Linux BSP 开发中,理解嵌入式 Linux 的整体骨架,比记住某一条编译命令更重要。BSP 工程师面对的不是单一程序,而是一套从芯片上电到用户空间服务可用的完整链路:引导加载程序初始化 DDR 与时钟,内核接管 CPU 与中断,驱动通过设备树获得板级硬件描述,根文件系统提供用户态运行环境,最终由 init 拉起业务进程。本节围绕这条主线,梳理内核架构、设备驱动模型、设备树、根文件系统与启动流程五个关键对象及其相互关系。
一、Linux 内核架构:分层与职责边界
Linux 内核在逻辑上可分为用户接口层、系统调用层、核心子系统层和硬件抽象层。用户程序通过系统调用进入内核态;VFS、网络协议栈、内存管理、进程调度、中断管理等核心子系统提供通用能力;具体硬件差异则由体系结构相关代码和驱动屏蔽。对 BSP 而言,最常改动的是驱动、设备树和板级配置,而不是核心调度器。
- 进程与调度:CFS 负责普通进程公平调度,实时策略用于音视频、工业控制等时延敏感场景。
- 内存管理:MMU 完成虚拟地址到物理地址映射,kmalloc/vmalloc 服务于内核,用户态通过页表隔离。
- VFS 与文件系统:向上提供统一 open/read/write/ioctl 接口,向下适配 ext4、f2fs、ubifs、squashfs 等。
- 设备驱动:把寄存器、中断、DMA、时钟、电源等硬件细节封装成内核对象。
二、设备驱动模型:总线、设备与驱动
Linux 2.6 之后引入统一设备模型,核心是 kobject、kset、device、driver、bus 以及 sysfs。设备与驱动注册到同一条总线上,由总线负责匹配;匹配成功后调用驱动的 probe,失败则调用 remove。Qualcomm 平台常见总线包括 platform、I2C、SPI、PCIe、USB 和 RPMSG 等。platform 总线用于描述 SoC 内部集成外设,如 I2C 控制器、GPIO 控制器、时钟控制器和电源管理 IC。
/* 典型 platform 驱动骨架 */
static int qcom_sample_probe(struct platform_device *pdev)
{
struct resource *res;
void __iomem *base;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
dev_info(&pdev->dev, "sample device probed\n");
return 0;
}
static const struct of_device_id qcom_sample_of_match[] = {
{ .compatible = "qcom,sample-device" },
{ }
};
MODULE_DEVICE_TABLE(of, qcom_sample_of_match);
static struct platform_driver qcom_sample_driver = {
.probe = qcom_sample_probe,
.driver = {
.name = "qcom-sample",
.of_match_table = qcom_sample_of_match,
},
};
module_platform_driver(qcom_sample_driver);
驱动模型的价值在于解耦:设备树描述“有什么硬件、接在哪里、用什么参数”,驱动描述“如何操作这类硬件”。同一驱动可服务多块板卡,板级差异通过 compatible、reg、interrupts、clocks、pinctrl 等属性传入。
三、设备树:板级硬件的声明式描述
设备树源文件 DTS 经 DTC 编译为 DTB,由 bootloader 传给内核。内核解析后生成 device_node 与 platform_device,再与驱动匹配。Qualcomm 平台通常采用多级包含:SoC 级 dtsi 描述公共控制器,板级 dts 覆盖引脚、电源、外设使能状态。常用属性包括 compatible、reg、interrupts、clocks、clock-names、pinctrl-0、status。
&i2c_1 {
status = "okay";
clock-frequency = <400000>;
touch@38 {
compatible = "goodix,gt911";
reg = <0x38>;
interrupt-parent = <&tlmm>;
interrupts = <45 IRQ_TYPE_EDGE_FALLING>;
reset-gpios = <&tlmm 12 GPIO_ACTIVE_LOW>;
};
};
四、根文件系统与启动流程
根文件系统是内核挂载后用户态程序的载体,包含 /bin、/sbin、/lib、/etc、/dev、/proc、/sys 等目录。嵌入式场景常用只读 squashfs 加可写 overlay,或 ubifs、ext4、f2fs。Qualcomm 设备通常由 ABL/XBL 引导,加载 boot.img 中的 kernel、dtb 与 ramdisk,再切换到 system/vendor 分区。
| 阶段 | 执行主体 | 关键动作 | 常见问题 |
|---|---|---|---|
| 上电复位 | Boot ROM | 校验并加载 XBL | 签名、熔丝配置错误 |
| 引导加载 | XBL/ABL | 初始化 DDR、时钟,加载 boot.img | DDR 参数、分区表异常 |
| 内核启动 | Linux kernel | 解压、解析 DTB、初始化子系统 | DTB 不匹配、驱动 probe 失败 |
| 挂载根文件系统 | kernel + initramfs | 挂载 rootfs,执行 /init | 分区损坏、挂载参数错误 |
| 用户态初始化 | init/systemd | 拉起服务、配置网络与显示 | 服务依赖、权限问题 |
五、案例与复盘:触摸屏不工作的排查路径
某 Qualcomm 板卡触摸屏无响应。按启动链路逐层排查:先确认 dmesg 中 I2C 控制器是否注册成功;再检查设备树 touch 节点 status 是否为 okay、reg 是否为 0x38;随后用 i2cdetect 扫描总线,确认器件是否应答;若应答正常但无中断,检查 pinctrl 与 interrupts 配置;最后确认驱动是否编入内核或作为模块加载。该案例说明,BSP 问题往往不是单点故障,而是设备树、驱动、时钟、电源与用户态服务共同作用的结果。
综上,Qualcomm Linux BSP 开发的核心能力,是沿着“引导—内核—设备树—驱动—根文件系统—用户态”这条链路建立系统观。只有把每个阶段的输入、输出和失败表现对应起来,才能在面对启动失败、外设不识别、服务起不来等问题时快速缩小范围,而不是盲目重编内核或反复刷机。