当前位置:首页>Linux>嵌入式面试刷题(四) | Linux系统/驱动相关问题整理

嵌入式面试刷题(四) | Linux系统/驱动相关问题整理

  • 2026-09-04 19:02:29
嵌入式面试刷题(四) | Linux系统/驱动相关问题整理

八股文是一种特殊文体,每篇文章包括破题、承题、起讲、入手、起股、中股、后股、束股八个部分,要求严格对仗,字数有限定,题目出自《四书》。 而现在大家常用八股文来指代面试中常见的一些知识、问题。 日常工作中我们往往围绕业务逻辑进行开发而忽略这些看似简单却可能不能立马给出精确回答的八股问题上。 所以如果你有找工作/换工作的计划,请拿出点时间看看八股,唤醒一下记忆深处的那段代码。

1. platform 框架的原理是什么?驱动匹配流程?

platform 框架原理:Linux 内核提供的一种虚拟总线机制,把没有实际物理总线的设备(如 SoC 内部外设)纳入统一的设备模型管理。

驱动匹配流程:

  1. 设备注册:通过设备树或代码注册 platform_device

  2. 驱动注册:platform_driver_register() 注册驱动

  3. 匹配:内核遍历总线上的设备和驱动,按优先级尝试匹配:

    ① 设备树 compatible 属性与驱动 of_match_table 匹配

    ② id_table 名字匹配

    ③ platform_driver.driver.name 与 platform_device.name 匹配

  4. 匹配成功后调用驱动的 probe() 函数,驱动在其中获取资源、初始化硬件

设备和驱动谁先注册都行,内核会在另一方注册时自动触发匹配。

2. probe 函数通常完成什么工作?

probe 函数是驱动的入口初始化函数,匹配成功后由内核自动调用,通常完成以下工作:

  • 解析设备信息:从设备树或platform_data获取寄存器地址、中断号、时钟等资源
  • 申请资源:ioremap映射寄存器、request_irq注册中断、clk_get获取时钟
  • 初始化硬件:配置寄存器、使能时钟和电源
  • 注册设备节点:向子系统注册(如 cdev、input_device、v4l2_device等),让用户态能访问
  • 分配私有数据结构:用 devm_kzalloc 分配驱动私有数据并关联到device

3. 主设备号与次设备号的作用,怎么申请?

  • 主设备号(Major):标识驱动程序
    • 内核通过主设备号找到对应的驱动
    • 同一类设备共享一个主设备号
  • 次设备号(Minor):标识具体设备实例
    • 驱动内部用次设备号区分不同设备
    • 如 /dev/ttyS0(次设备号0)和 /dev/ttyS1(次设备号1)
  • MKDEV(major, minor):将主设备号和次设备号组合成完整的设备号(dev_t)
  • 提取设备号:MAJOR(dev) / MINOR(dev)
  • 分配方式:
    • 静态:register_chrdev_region(dev, count, name)
    • 动态(推荐):alloc_chrdev_region(&dev, 0, count, name)

4. 用户空间和内核空间的通信方式有哪些?

  • 系统调用:最基本的方式(open/read/write/ioctl)
  • procfs:/proc/ 下创建文件,用户cat/echo操作
  • sysfs:/sys/ 下创建属性文件
  • ioctl:通过设备文件发送控制命令和数据
  • netlink socket:异步双向通信,支持多播
  • mmap:共享内存区域,零拷贝
  • copy_to_user/copy_from_user:read/write中的数据传递
  • debugfs:调试用虚拟文件系统
  • 字符设备:ioctl/unlocked_ioctl

5. Linux驱动中有哪些内存分配函数?

  • kmalloc:物理连续,基于slab,快速,适合小块(<128KB)
  • kzalloc:= kmalloc + memset(0),分配并清零
  • kcalloc:= 数组形式分配,内部检查溢出
  • vmalloc:虚拟连续但物理可能不连续,适合大块,开销大
  • devm_kmalloc:设备管理版,设备移除时自动释放

小内存用kmalloc,大内存用vmalloc,驱动中优先devm_版本。

6. container_of(ptr, type, member)宏的作用和原理

作用:从成员指针反推出包含它的结构体指针。

  • 定义:container_of(ptr, type, member)

  • 原理:

    (type *)((char *)ptr - offsetof(type, member))
    • 用成员地址 减去 成员在结构体中的偏移量,得到结构体首地址
  • 使用场景(非常常见):

    • 从 file->private_data 获取设备结构体
    • 从 cdev 指针获取包含它的自定义设备结构体
    • 链表遍历中从 list_head 获取数据结构体

7. 编译器的优化等级-O0、-O1、-O2、-O3有什么区别?优化可能导致什么问题?

-O0:不优化,调试方便但运行慢。

-O1:基本优化。

-O2:推荐优化级别,平衡性能和编译速度。

-O3:激进优化(循环展开、向量化等)。

优化可能导致的问题:

  • 调试困难:变量被优化掉、代码顺序改变
  • volatile遗漏暴露:不加volatile的硬件寄存器访问被优化掉
  • 时序变化:优化后代码执行速度变化,可能影响精确延时
  • 未定义行为暴露:优化器利用UB假设做激进优化

8. 孤儿进程、僵尸进程、守护进程分别是什么?

  • 孤儿进程:父进程先于子进程退出,子进程变成孤儿,被 init(PID=1)进程收养,由 init 负责回收。无害
  • 僵尸进程:子进程退出后,父进程没有调用 wait()/waitpid() 回收其退出状态。子进程的 task_struct 还残留在内核中,状态为 Z(Zombie)。有害(占用 PID 和内核资源)
  • 守护进程(Daemon):在后台运行的服务进程,与终端脱离关联。如 sshd、crond。通常通过两次 fork() + setsid() 创建

9. Linux中的softirq、tasklet、workqueue的区别

三种下半部机制的核心区别:

  • softirq:静态定义,可多CPU并行执行,性能最高,内核内部用(网络/块设备)
  • tasklet:基于softirq,同一tasklet不会多CPU并行,不能睡眠
  • workqueue:基于内核线程,可以睡眠,可延时执行

选择原则:

  • 需要睡眠 → workqueue
  • 不需要睡眠且需快速执行 → tasklet
  • 高性能内核路径 → softirq

10. Linux内核模块的加载和卸载过程

内核模块的加载和卸载过程:

加载(insmod/modprobe):

  • 读取.ko文件,解析ELF格式
  • 分配内核内存,拷贝代码和数据
  • 解决符号引用(链接内核导出符号)
  • 调用module_init()指定的函数

卸载(rmmod):

  • 检查引用计数,确认没人在用
  • 调用module_exit()指定的清理函数
  • 释放模块占用的内存

modprobe比insmod多了自动处理依赖关系的能力。

最新文章

随机文章