以 Linux 为代表的自由操作系统的很多优点之一,是它们的内部是开放给所有人看的。操作系统,曾经是一个隐藏的神秘的地方,它的代码只局限于少数的程序员,现在已准备好让任何具备必要技能的人来检查,理解以及修改。
Linux 已经帮助使操作系统民主化,Linux 内核保留有大量的复杂的代码,但是,那些想要成为内核 hacker 的人需要一个入口点,这样他们可以进入代码中,不会被代码的复杂性压倒,通常,设备驱动提供了这样的门路。 目录第 1 章 设备驱动简介................................... 1 1.1. 驱动程序的角色................................ 1 1.2. 划分内核............................................ 2 1.2.1. 可加载模块................................ 3 1.3. 设备和模块的分类............................ 4 1.4. 安全问题............................................ 6 1.5. 版本编号............................................ 7 1.6. 版权条款............................................ 8 1.7. 加入内核开发社团............................ 9 1.8. 本书的内容........................................ 9 第 2 章 建立和运行模块........................ 11 2.1. 设置你的测试系统.......................... 11 2.2. HELLO WORLD 模块......................... 11 2.3. 内核模块相比于应用程序............... 13 2.3.1. 用户空间和内核空间............... 14 2.3.2. 内核的并发.............................. 15 2.3.3. 当前进程.................................. 15 2.3.4. 几个别的细节.......................... 16 2.4. 编译和加载...................................... 16 2.4.1. 编译模块.................................. 16 2.4.2. 加载和卸载模块...................... 18 2.4.3. 版本依赖.................................. 19 2.4.4. 平台依赖性.............................. 20 2.5. 内核符号表...................................... 21 2.6. 预备知识.......................................... 22 2.7. 初始化和关停.................................. 22 2.7.1. 清理函数.................................. 23 2.7.2. 初始化中的错误处理............... 24 2.7.3. 模块加载竞争.......................... 26 2.8. 模块参数.......................................... 26 2.9. 在用户空间做.................................. 28 2.10. 快速参考........................................ 29 第 3 章 字符驱动.................................... 32 3.1. SCULL 的设计................................... 32 3.2. 主次编号.......................................... 33 3.2.1. 设备编号的内部表示............... 33 3.2.2. 分配和释放设备编号............... 34 3.2.3. 主编号的动态分配.................. 35 3.3. 一些重要数据结构.......................... 37 3.3.1. 文件操作.................................. 37 3.3.2. 文件结构.................................. 41 3.3.3. inode 结构................................ 43 3.4. 字符设备注册.................................. 43 3.4.1. scull 中的设备注册.................. 44 3.4.2. 老方法...................................... 45 3.5. OPEN 和 RELEASE .............................. 45 3.5.1. open 方法................................. 45 3.5.2. release 方法.............................. 47 3.6. SCULL 的内存使用........................... 47 3.7. 读和写.............................................. 50 3.7.1. read 方法.................................. 52 3.7.2. write 方法................................. 53 3.7.3. readv 和 writev ......................... 55 3.8. 使用新设备...................................... 55 3.9. 快速参考.......................................... 56 第 4 章 调试技术.................................... 58 4.1. 内核中的调试支持.......................... 58 4.2. 用打印调试...................................... 60 4.2.1. printk......................................... 60 4.2.2. 重定向控制台消息.................. 62 4.2.3. 消息是如何记录的.................. 62 4.2.4. 打开和关闭消息...................... 63 4.2.5. 速率限制.................................. 65 4.2.6. 打印设备编号.......................... 65 4.3. 用查询来调试.................................. 66 4.3.1. 使用 /proc 文件系统................ 66 4.3.2. ioctl 方法.................................. 73 4.4. 使用观察来调试.............................. 73 4.5. 调试系统故障.................................. 75 4.5.1. oops 消息.................................. 76 4.5.2. 系统挂起.................................. 78 4.6. 调试器和相关工具.......................... 80 4.6.1. 使用 gdb ................................... 80 4.6.2. kdb 内核调试器....................... 83 4.6.3. kgdb 补丁................................. 85 4.6.4. 用户模式 Linux 移植............... 85 4.6.5. Linux 追踪工具........................ 86 4.6.6. 动态探针.................................. 86 第 5 章 并发和竞争情况........................ 87 5.1. SCULL 中的缺陷............................... 87 5.2. 并发和它的管理.............................. 88 5.3. 旗标和互斥体.................................. 89 5.3.1. Linux 旗标实现........................ 89 5.3.2. 在 scull 中使用旗标................. 91 5.3.3. 读者/写者旗标......................... 92 5.4. COMPLETIONS 机制.......................... 93 5.5. 自旋锁.............................................. 95 5.5.1. 自旋锁 API 简介...................... 95 5.5.2. 自旋锁和原子上下文............... 96 5.5.3. 自旋锁函数.............................. 97 5.5.4. 读者/写者自旋锁..................... 98 5.6. 锁陷阱.............................................. 99 5.6.1. 模糊的规则.............................. 99 5.6.2. 加锁顺序规则.......................... 99 5.6.3. 细 -粗- 粒度加锁.................... 100 5.7. 加锁的各种选择............................ 100 5.7.1. 不加锁算法............................ 100 5.7.2. 原子变量................................ 101 5.7.3. 位操作.................................... 103 5.7.4. seqlock 锁............................... 104 5.7.5. 读取-拷贝-更新...................... 105 5.8. 快速参考........................................ 106 第 6 章 高级字符驱动操作.................. 111 6.1. IOCTL 接口...................................... 111 6.1.1. 选择 ioctl 命令....................... 112 6.1.2. 返回值.................................... 115 6.1.3. 预定义的命令........................ 115 6.1.4. 使用 ioctl 参数....................... 116 6.1.5. 兼容性和受限操作................ 118 6.1.6. ioctl 命令的实现.................... 119 6.1.7. 不用 ioctl 的设备控制............ 120 6.2. 阻塞 I/O.......................................... 121 6.2.1. 睡眠的介绍............................ 122 6.2.2. 简单睡眠................................ 122 6.2.3. 阻塞和非阻塞操作................ 124 6.2.4. 一个阻塞 I/O 的例子.............. 125 6.2.5. 高级睡眠................................ 127 6.2.6. 测试 scullpipe 驱动................ 134 6.3. POLL 和 SELECT............................... 135 6.3.1. 与 read 和 write 的交互.......... 137 6.3.2. 底层的数据结构.................... 139 6.4. 异步通知........................................ 140 6.4.1. 驱动的观点............................ 141 6.5. 移位一个设备................................ 142 6.5.1. llseek 实现.............................. 143 6.6. 在一个设备文件上的存取控制..... 144 6.6.1. 单 open 设备.......................... 144 6.6.2. 一次对一个用户限制存取..... 145 6.6.3. 阻塞 open 作为对 EBUSY 的替代.................................................. 146 6.6.4. 在 open 时复制设备............... 148 6.7. 快速参考........................................ 150 第 7 章 时间, 延时, 和延后工作............ 154 7.1. 测量时间流失................................ 154 7.1.1. 使用 jiffies 计数器................. 154 7.1.2. 处理器特定的寄存器............. 156 7.2. 获知当前时间................................ 158 7.3. 延后执行........................................ 159 7.3.1. 长延时.................................... 160 7.3.2. 短延时.................................... 164 7.4. 内核定时器.................................... 165 7.4.1. 定时器 API ............................. 166 7.4.2. 内核定时器的实现................ 169 7.5. TASKLETS 机制............................... 170 7.6. 工作队列........................................ 172 7.6.1. 共享队列................................ 174 7.7. 快速参考........................................ 176 7.7.1. 时间管理................................ 176 7.7.2. 延迟........................................ 177 7.7.3. 内核定时器............................ 178 7.7.4. Tasklets 机制.......................... 178 7.7.5. 工作队列................................ 179 第 8 章 分配内存.................................. 181 8.1. KMALLOC 的真实故事................... 181 8.1.1. flags 参数............................... 181 8.1.2. size 参数................................ 184 8.2. 后备缓存........................................ 184 8.2.1. 一个基于 Slab 缓存的 scull: scullc ................................................ 186 8.2.2. 内存池.................................... 187 8.3. GET_FREE_PAGE 和其友................. 188 8.3.1. 一个使用整页的 scull: scullp . 189 8.3.2. alloc_pages 接口.................... 190 8.3.3. vmalloc 和 其友...................... 191 8.3.4. 一个使用虚拟地址的 scull : scullv ................................................ 193 8.4. 每-CPU 的变量.............................. 194 8.5. 获得大量缓冲................................ 196 8.5.1. 在启动时获得专用的缓冲..... 196 8.6. 快速参考........................................ 197 第 9 章 与硬件通讯.............................. 201 9.1. I/O 端口和 I/O 内存....................... 201 9.1.1. I/O 寄存器和常规内存........... 202 9.2. 使用 I/O 端口................................. 203 9.2.1. I/O 端口分配.......................... 204 9.2.2. 操作 I/O 端口......................... 204 9.2.3. 从用户空间的 I/O 存取.......... 205 9.2.4. 字串操作................................ 206 9.2.5. 暂停 I/O.................................. 206 9.2.6. 平台依赖性............................ 207 9.3. 一个 I/O 端口例子......................... 209 9.3.1. 并口纵览................................ 209 9.3.2. 一个例子驱动........................ 210 9.4. 使用 I/O 内存................................. 211 9.4.1. I/O 内存分配和映射............... 212 9.4.2. 存取 I/O 内存......................... 213 9.4.3. 作为 I/O 内存的端口.............. 214 9.4.4. 重用 short 为 I/O 内存............ 215 9.4.5. 在 1 MB 之下的 ISA 内存....... 215 9.4.6. isa_readb 和其友................... 217 9.5. 快速参考........................................ 217 第 10 章 中断处理................................ 220 10.1. 准备并口...................................... 220 10.2. 安装一个中断处理...................... 220 10.2.1. /proc 接口............................. 223 10.2.2. 自动检测 IRQ 号.................. 224 10.2.3. 快速和慢速处理.................. 228 10.2.4. 实现一个处理...................... 229 10.2.5. 处理者的参数和返回值....... 232 10.2.6. 使能和禁止中断.................. 233 10.3. 前和后半部.................................. 234 10.3.1. Tasklet 实现.......................... 235 10.3.2. 工作队列.............................. 236 10.4. 中断共享...................................... 237 10.4.1. 安装一个共享的处理者....... 237 10.4.2. 运行处理者.......................... 238 10.4.3. /proc 接口和共享中断.......... 239 10.5. 中断驱动 I/O................................ 239 10.5.1. 一个写缓存例子.................. 240 10.6. 快速参考...................................... 243 第 11 章 内核中的数据类型................ 245 11.1. 标准 C 类型的使用...................... 245 11.2. 安排一个明确大小给数据项....... 246 11.3. 接口特定的类型.......................... 247 11.4. 其他移植性问题.......................... 248 11.4.1. 时间间隔.............................. 248 11.4.2. 页大小.................................. 248 11.4.3. 字节序.................................. 248 11.4.4. 数据对齐.............................. 249 11.4.5. 指针和错误值...................... 250 11.5. 链表.............................................. 251 11.6. 快速参考...................................... 255 第 12 章 PCI 驱动................................. 257 12.1. PCI 接口....................................... 257 12.1.1. PCI 寻址............................... 257 12.1.2. 启动时间.............................. 260 12.1.3. 配置寄存器和初始化........... 261 12.1.4. MODULEDEVICETABLE 宏 264 12.1.5. 注册一个 PCI 驱动............... 264 12.1.6. 老式 PCI 探测...................... 266 12.1.7. 使能 PCI 设备...................... 267 12.1.8. 存取配置空间...................... 267 12.1.9. 存取 I/O 和内存空间............ 268 12.1.10. PCI 中断............................. 270 12.1.11. 硬件抽象............................ 270 12.2. 回顾: ISA...................................... 272 12.2.1. 硬件资源.............................. 272 12.2.2. ISA 编程............................... 272 12.2.3. 即插即用规范...................... 273 12.3. PC/104 和 PC/104+ ...................... 273 12.4. 其他的 PC 总线............................ 274 12.4.1. MCA 总线............................. 274 12.4.2. EISA 总线............................. 274 12.4.3. VLB 总线.............................. 274 12.5. SBUS............................................. 275 12.6. NUBUS 总线................................. 275 12.7. 外部总线...................................... 275 12.8. 快速参考...................................... 276 第 13 章 USB 驱动............................... 278 13.1. USB 设备基础知识...................... 279 13.1.1. 端点...................................... 279 13.1.2. 接口...................................... 281 13.1.3. 配置...................................... 282 13.2. USB 和 SYSFS ............................... 282 13.3. USB 的 URBS................................ 284 13.3.1. 结构 struct urb...................... 285 13.3.2. 创建和销毁 urb.................... 291 13.3.3. 提交 urb................................ 294 13.3.4. 完成 urb: 完成回调处理者... 294 13.3.5. 取消 urb................................ 295 13.4. 编写一个 USB 驱动..................... 295 13.4.1. 驱动支持什么设备............... 295 13.4.2. 注册一个 USB 驱动.............. 297 13.4.3. 提交和控制一个 urb............ 303 13.5. 无 URB 的 USB 传送..................... 304 13.5.1. usb_bulk_msg 接口............... 305 13.5.2. usb_control_msg 接口........... 306 13.5.3. 使用 USB 数据函数.............. 307 13.6. 快速参考...................................... 308 第 14 章 LINUX 设备模型..................... 311 14.1. KOBJECTS, KSETS 和 SUBSYSTEMS 312 14.1.1. Kobject 基础......................... 313 14.1.2. kobject 层次, kset, 和子系统. 316 14.2. 低级 SYSFS 操作........................... 319 14.2.1. 缺省属性.............................. 319 14.2.2. 非缺省属性.......................... 321 14.2.3. 二进制属性.......................... 321 14.2.4. 符号连接.............................. 322 14.3. 热插拔事件产生.......................... 322 14.3.1. 热插拔操作.......................... 323 14.4. 总线, 设备, 和驱动...................... 324 14.4.1. 总线...................................... 324 14.4.2. 设备...................................... 327 14.4.3. 设备驱动.............................. 331 14.5. 类.................................................. 333 14.5.1. class_simple 接口................. 334 14.5.2. 完整的类接口...................... 335 14.6. 集成起来...................................... 337 14.6.1. 添加一个设备...................... 338 14.6.2. 去除一个设备...................... 341 14.6.3. 添加一个驱动...................... 341 14.6.4. 去除一个驱动...................... 342 14.7. 热插拔.......................................... 342 14.7.1. 动态设备.............................. 342 14.7.2. /sbin/hotplug 工具................ 343 14.7.3. 使用 /sbin/hotplug ................ 347 14.8. 处理固件...................................... 349 14.8.1. 内核固件接口...................... 350 14.8.2. 它如何工作.......................... 350 14.9. 快速参考...................................... 351 14.9.1. Kobjects结构........................ 351 14.9.2. sysfs 操作.............................. 352 14.9.3. 总线, 设备, 和驱动............... 352 14.9.4. 类.......................................... 353 14.9.5. 固件...................................... 354 第 15 章 内存映射和 DMA.................. 355 15.1. LINUX 中的内存管理................... 355 15.1.1. 地址类型.............................. 355 15.1.2. 物理地址和页...................... 357 15.1.3. 高和低内存.......................... 357 15.1.4. 内存映射和 struct page......... 358 15.1.5. 页表...................................... 360 15.1.6. 虚拟内存区.......................... 360 15.1.7. 进程内存映射...................... 363 15.2. MMAP 设备操作........................... 363 15.2.1. 使用 remap_pfn_range.......... 365 15.2.2. 一个简单的实现.................. 366 15.2.3. 添加 VMA 的操作................ 366 15.2.4. 使用 nopage 映射内存.......... 367 15.2.5. 重新映射特定 I/O 区............ 369 15.2.6. 重新映射 RAM..................... 370 15.2.7. 重映射内核虚拟地址........... 373 15.3. 进行直接 I/O................................ 374 15.3.1. 异步 I/O................................ 376 15.4. 直接内存存取.............................. 379 15.4.1. 一个 DMA 数据传输的概况. 379 15.4.2. 分配 DMA 缓冲.................... 380 15.4.3. 总线地址.............................. 381 15.4.4. 通用 DMA 层........................ 382 15.4.5. ISA 设备的 DMA.................. 390 15.5. 快速参考...................................... 395 15.5.1. 介绍性材料.......................... 395 15.5.2. 实现 mmap ........................... 396 15.5.3. 实现直接 I/O........................ 397 15.5.4. 直接内存存取...................... 397 第 16 章 块驱动.................................... 400 16.1. 注册.............................................. 400 16.1.1. 块驱动注册.......................... 400 16.1.2. 磁盘注册.............................. 401 16.1.3. 在 sbull 中的初始化.............. 403 16.1.4. 注意扇区大小...................... 405 16.2. 块设备操作.................................. 405 16.2.1. open 和 release 方法............. 405 16.2.2. 支持可移出的介质............... 407 16.2.3. ioctl 方法.............................. 407 16.3. 请求处理...................................... 408 16.3.1. 对请求方法的介绍............... 408 16.3.2. 一个简单的请求方法........... 409 16.3.3. 请求队列.............................. 411 16.3.4. 请求的分析.......................... 414 16.3.5. 请求完成函数...................... 419 16.4. 一些其他的细节.......................... 423 16.4.1. 命令预准备.......................... 423 16.4.2. 被标识的命令排队............... 424 16.5. 快速参考...................................... 426 第 17 章 网络驱动................................ 430 17.1. SNULL 是如何设计的................... 430 17.1.1. 分配 IP 号............................ 431 17.1.2. 报文的物理传送.................. 433 17.2. 连接到内核.................................. 433 17.2.1. 设备注册.............................. 433 17.2.2. 初始化每一个设备............... 435 17.2.3. 模块卸载.............................. 436 17.3. NET_DEVICE 结构的详情.............. 437 17.3.1. 全局信息.............................. 437 17.3.2. 硬件信息.............................. 437 17.3.3. 接口信息.............................. 438 17.3.4. 设备方法.............................. 442 17.3.5. 公用成员.............................. 444 17.4. 打开与关闭.................................. 445 17.5. 报文传送...................................... 446 17.5.1. 控制发送并发...................... 448 17.5.2. 传送超时.............................. 448 17.5.3. 发散/汇聚 I/O....................... 449 17.6. 报文接收...................................... 450 17.7. 中断处理...................................... 452 17.8. 接收中断缓解.............................. 454 17.9. 连接状态的改变.......................... 456 17.10. SOCKET 缓存.............................. 457 17.10.1. 重要成员变量.................... 457 17.10.2. 作用于 socket 缓存的函数. 458 17.11. MAC 地址解析.......................... 460 17.11.1. 以太网使用 ARP................ 460 17.11.2. 不考虑 ARP........................ 461 17.11.3. 非以太网头部.................... 461 17.12. 定制 IOCTL 命令......................... 462 17.13. 统计信息.................................... 463 17.14. 多播............................................ 464 17.14.1. 多播的内核支持................ 465 17.14.2. 典型实现............................ 466 17.15. 几个其他细节............................ 467 17.15.1. 独立于媒介的接口支持..... 467 17.15.2. ethtool 支持........................ 468 17.15.3. netpoll ................................. 468 17.16. 快速参考.................................... 468 第 18 章 TTY 驱动............................... 472 18.1. 一个小 TTY 驱动......................... 474 18.1.1. 结构 struct termios ............... 475 18.2. TTY_DRIVER 函数指针................. 478 18.2.1. open 和 close ........................ 478 18.2.2. 数据流.................................. 481 18.2.3. 其他缓冲函数...................... 482 18.2.4. 无 read 函数?....................... 483 18.3. TTY 线路设置............................. 484 18.3.1. set_termios 函数................... 484 18.3.2. tiocmget 和 tiocmset .............. 486 18.4. IOCTLS 函数.................................. 487 18.5. TTY 设备的 PROC 和 SYSFS 处理.. 490 18.6. TTY_DRIVER 结构的细节.............. 491 18.7. TTY_OPERAIONS 结构的细节........ 493 18.8. TTY_STRUCT 结构的细节.............. 495 18.9. 快速参考...................................... 498
|