面灵AI→

全志科技嵌入式软件一面面经

轮次
一面
时间
2026-10
来源
牛客网

《面试题目》

  1. 自我介绍。
  2. 介绍一下做过的 Linux 项目,整体架构是怎样的?
  3. 项目中写了移植 U-Boot 和 Linux 内核,具体做了哪些工作?U-Boot 是如何加载 Linux 内核和设备树的?
  4. 交叉编译工具链是怎么配置的?
  5. 设备树是什么?为什么要用它?
  6. 板级配置里改了哪些东西?
  7. 启动调试过程中遇到过什么问题,怎么定位的?
  8. 编译出的启动镜像、内核镜像分别是什么,烧录到哪里?

《参考解析》

Linux 项目的整体架构怎么讲。原帖作者的思路是把项目按 Bootloader、Kernel、Driver、Application 四个层次表达清楚,这个拆法确实是最稳的。Bootloader 层负责最早上电时的时钟与 DDR 初始化、把内核与设备树搬到内存并跳转执行;Kernel 层负责进程调度、内存管理、设备驱动框架;Driver 层是具体外设的驱动实现或适配(I²C、SPI、GPIO、显示、网络等),要说明是自己写的还是在内核已有驱动上做适配与调参;Application 层是业务逻辑。讲的时候要带上「数据/控制怎么在这四层之间流动」的一条主线,比如用户态应用通过字符设备节点下发命令、驱动收到后操作寄存器、外设通过中断回数据、驱动再唤醒等待队列上的进程。只罗列层次不接主线,面试官会认为你只是把别人的板子跑起来了。

移植 U-Boot 具体做了哪些事。按顺序是:拿到厂商或社区的源码 → 板级配置(在 board/ 与 configs/ 下新增板级目录与 _defconfig,改 DDR 参数、时钟树、串口波特率、启动介质)→ 配置交叉编译工具链(CROSS_COMPILE,注意工具链版本与内核版本匹配)→ 调整启动参数与设备树(bootargs 里的 console=、root=、rootfstype=)→ 编译生成 u-boot.bin/u-boot-with-spl → 用烧录工具或 SD 卡烧到板子上 → 上电调试。调试常见问题:串口无输出(时钟或波特率不对)、DDR 初始化失败(参数表与颗粒不符)、进不了内核(load 地址或 bootargs 不对)。

U-Boot 如何加载内核与设备树。典型流程是:SPL(第一阶段)初始化最小硬件并把完整 U-Boot 搬到 DDR,完整 U-Boot 起来后初始化串口、网口、存储等;然后把内核镜像(Image 或 zImage)与设备树 blob(.dtb)从启动介质(eMMC、SD、NAND、TFTP)读到内存的指定地址,把设备树地址通过 bootargs/寄存器(ARM64 上是 x0)或 bootm 的参数传给内核,最后跳转到内核入口。要能说出两个细节:设备树地址与 initrd 的地址不能重叠;内核启动后早期会解析 bootargs 里的 console、root 决定根文件系统从哪挂载。问「为什么要分两个阶段」,答案是 SPL 要在 DDR 还没初始化、可用 SRAM 极小的约束下工作,所以它必须尽量小,把复杂初始化留给完整 U-Boot。

设备树的作用。设备树(Device Tree)把「板子上有什么硬件、接在哪个控制器上、地址与中断号是多少」这类板级信息从内核源码里剥离出来,用 .dts/.dtsi 描述、编译成 .dtb 交给内核解析。好处是同一份内核镜像可以配不同的设备树跑在不同板子上,驱动只负责「这类控制器怎么做」,不再硬编码板级资源。常见的面试延伸:compatible 属性怎么匹配驱动(驱动里的 of_device_id 表)、status = "okay"/"disabled" 怎么裁剪外设、修改设备树后要用 dtc 重新编译或让 U-Boot 加载新的 .dtb。

嵌入式岗位的复习主线。这家做 SoC 与嵌入式方案的公司,一面通常就压在这条链路上:从启动流程到驱动到应用。准备时最好能把手上那个项目从「上电到业务跑起来」完整串一遍,每一层的地址、镜像名、配置项、遇到的问题都能说出来,比背零散的知识点有效得多。