Linux device drivers 3rd Edition reading notes

Chapter 1 & 2: An introduction to device driver & Building and Running modules
1. Concurrent, Security -- module writting notes
2. Kernel stack is small, normally one page(4K). So don't create a lot of local variables and don't have a long call stack.
3. Kernel can't handle float pointing computing.
4. Compiling & Build:
   obj-m := module.o
   module-objs := file1.o file2.o
   make -C ~/kernel-2.6 M=`pwd` modules
5. /proc/modules saves all modules load. lsmod uses this file as well.
   Entries in /proc/modules contain the module name, the amount of memory each module occupies, and the usage count
6. Module codes will be linked with vermagic.o, this makes: when insmod, it checks the version in module codes and the version of current kernel, if mismatch, insmod failed.
7. Use EXPORT_SYMBOL/EXPORT_SYMBOL_GPL, modules can export symbols to other module using. E.g: lp is the module we use, and the parport/parport_pc is the underlying modules. So, module symbol export can be used to define interfaces.
8. modprobe just search /lib/modules folder to find drivers, and insmod can be used to insert a module into kernel in the specified driver file path.
9. __init & __exit mocros. These are used to decorate the init & exit functions. __init tells kernel this is an init function and only be called when the module is loaded. After module loaded, the function will be dropped in kernel to save memory. __exit tells kernel this is the function which can ONLY be called while module unloading. So, IF YOU WILL CALL YOUR CLEANUP FUNCTIONS IN INIT FUNCTION, DON'T ADD __exit PREFIX IN THESE CLEANUP FUNCTION, BECAUSE THE FUNCTION PREFIXED WITH __exit CAN ONLY BE CALLED WHEN THE MODULE UNLOADING.
10. Module param: insmod xxx a=1 b=2
   module_param(howmany, int, S_IRUGO);
   module_param_array(name,type,num,perm);  // array param is allowed
   The permission param in module_param/module_param_array is used to tell kernel whether should create an entry under /sys/module, and if should, the permission of this entry(file). After that, changes to this entry can be got in module by module param. BUT THE MODULE WILL BE KNOWN ABOUT THIS AUTOMATICALLY, we should handle the module param update ourselves.

==================================================================================================
Chapter 3: Char drivers
1. major number -- related with one perticular driver. minor number -- kernel doesn't care about it, it means a lot for drivers. E.g: if a driver implements multiple device files, it can distinguish them by minor number.
2. MKDEV macro to generate a dev_t structure. MAJOR & MINOR macros can be used to check out the major & minor numbers in a dev_t structure.
3. alloc_chrdev_region -- request a major number from kernel and register it.
   register_chrdev_region -- regist a major number manually
   unregist_chrdev_region -- free the major number
   /proc/devices -- list devices and their major numbers. You can check this file to get a major number free to use
4. Every file has a file structure in kernel(named "struct file"). There is a member named f_op in this structure which is the type of file_operations. Driver should implement the function pointers in f_op. When the open system call called, the open function in kernel will be called first, then the function will call driver's open function pointer.
5. Lots of function pointers in f_op. Refer to Page 70 for details. Sample code:
   struct file_operations scull_fops = {
       .owner =    THIS_MODULE,
       .llseek =   scull_llseek,
       .read =     scull_read,
       .write =    scull_write,
       .ioctl =    scull_ioctl,
       .open =     scull_open,
       .release =  scull_release,
};
6. inode. inode represents a file while "struct file" represents a FD. So a file can be opened multiple times which generates a lot of "struct file"s, but inode only has one for one file.
7. cdev_alloc/cdev_init/cdev_add -- register the char device driver.
8. kmalloc/kfree. kmalloc is not the good way to malloc a large area of memory.
9. Why the user space pointer should NOT be dereferenced directly? Here are the reasons:
   (1) Depending on which architecture your driver is running on, and how the kernel was configured, the user-space pointer may not be valid while running in kernel mode at all. There may be no mapping for that address, or it could point to some other, random data.
   (2) Even if the pointer does mean the same thing in kernel space, user-space mem-ory is paged, and the memory in question might not be resident in RAM when the system call is made. Attempting to reference the user-space memory directly could generate a page fault, which is something that kernel code is not allowedto do. The result would be an “oops,” which would result in the death of the process that made the system call.
   (3) The pointer in question has been supplied by a user program, which could be buggy or malicious. If your driver ever blindly dereferences a user-supplied pointer, it provides an open doorway allowing a user-space program to access or overwrite memory anywhere in the system. If you do not wish to be responsible for compromising the security of your users’ systems, you cannot ever derefer-ence a user-space pointer directly.
10. Use copy_to_user & copy_from_user to access user space pointers. These functions act like memcpy with differences: (1) The memory pointed by user space pointer may be in swapped in disk right now, so these "memcpy" like functions will execute longer, so MAKE SURE your driver code is thread/process safe. (2) These functions check whether the user space pointer is valid.
11. use "strace" to trace the system call -- params and return values.

==================================================================================================
Chapter 4: Debugging Techniques
1. When config kernel, there is a "kernel hacking" menu in it. All entries in it are about kernel debugging. E.g: magic sysrq function/debug slab(alloced memory will be set to 0xa5, after kfree, it will be set to 0xb6)/INIT debug... and etc.
2. Print debugging skills:
   (1)  printk将信息打印到当前的console上,这个console可以是一个文本的terminal,也可以是一个串口或并口打印机。要求是当前message的priority比console_loglevel小。记住:printk的message结尾要有一个\n,否则消息不会被打印出来。
   (2) 如果klogd和syslogd都在运行的话,printk的信息就会被存储到/var/log/messages中。这和console_loglevel无关,所有的消息都会被记录到文件中。
   (3) 如果klogd没有运行,那么,通过读取/proc/kmsg也可以看到信息,dmesg命令也会打印这些信息。
3. 如何修改console_loglevel?有很多办法:
   (1) 调用sys_syslog系统调用。
   (2) 启动klogd的时候加上-c option。
   (3) 用程序修改。这里书中没给出程序,可以到Oreilly的FTP上下载。
   (4) 修改文件/proc/sys/kernel/printk。这个文件有四项内容,看下面一段的描述。可以直接给这个文件设置一个value,这就表示修改current loglevel。
4. How the printk texts can be displayed in a lot of places:
   The printk function writes messages into a circular buffer that is__LOG_BUF_LEN bytes long: a value from 4 KB to 1 MB chosen while configuring the kernel. The function then wakes any process that is waiting for messages, that is, any process that is sleep-ing in the syslog system call or that is reading /proc/kmsg.
5. About klogd & syslogd:
   如果klogd启动,那么klogd将message传递给syslogd,syslogd负责将信息记录进入文件。facility是LOG_KERN,priority和printk中的对应。
   如果klogd没有启动,那么自然message就不会被读取,除非用dmesg或是自己读取/proc/kmsg
   如果不喜欢syslogd,那么可以配置klogd让他将信息直接写入文件。或者干脆klogd也不启动,象上面所说,将信息发送到另外一个专门的console上,或者单独开一个终端,读取/proc/kmsg即可。
6. Driver can implement it's own /proc or /sys files to expose a lot of driver internals to the user space. It's better than use printk heavily.
7. read_proc/create_proc_read_entry can be used to create & response read proc files. But this read_proc just permit us to return ONE PAGE data.
8. To avoid the ONE PAGE issue in read_proc, seq_file interface comes up. Four function pointers should be implemented:
   start/stop/next/show
   Use create_proc_entry to create the proc file and associate with the four functions listed above.
   Refer to Page 109 for more details.
9. IOCTL is another way to debugging. No page limit. More generic than read_proc & seq_file interface.
10. Oops message reading. Refer to "Debug Hacks" book.
11. Magic SysRq key. Refer to "Debug Hacks" book.
12. Use GDB debug kernel: can ONLY check variables, CAN'T set breakpoints, change variables...
   CONFIG_DEBUG_INFO selected when config kernel
   gdb /usr/src/linux/vmlinux /proc/kcore -- vmlinux is not stripped/compressed linux kernel file. /proc/kcore like other proc entries, it outputs data when you read it automatically.
   How to debug loadable module: (1) load the module (2) check the /sys/module/<module name>/sections to check out the section address(.text, .bss, .data...) (3) Then use gdb "add-symbol-file" command: add-symbol-file .../scull.ko 0xd0832000 -s .bss 0xd0837100 -s .data 0xd0836be0
13. kdb并不是官方的kernel builtin debugger。是oss.sgi.com提供的,而且现在只支持IA-32。这就没什么用了。ARM都不支持就比较麻烦了。
14. 有两个对gdb的patch,他们都叫kgdb。patch之后的gdb就能debug kernel,能设置断点,修改数据。工作模式也和平常的不一样,一般是被debug的独立在一台机器上,开发人员在另外一台机器上,两台机器用串口线互联,然后远程debug。

==================================================================================================
Chapter 5: Concurrency and Race Conditions
1. sema_init -- semaphone init. Semaphone has P, V functions.
2. DECLARE_MUTEX/DECLARE_MUTEX_LOCKED -- Declare a static mutex(actually it is a semaphone with value 1).
3. init_mutex/init_mutex_locked -- allocate a mutex at runtime
4. down/down_interruptible/down_trylock -- down_interruptible can be cancalled, so check the return value of the function to see whether we got this semaphone or the down operation was cancalled.
5. up - the semaphone V function
6. init_rwsem/down_read/down_read_trylock/up_read/down_write/down_write_trylock/up_write -- init a read/write semaphone. Read/write semaphone allows multiple read operation at one time, but if has write operation, all read/write trying will be blocked. Like windows' SRWLock. It can improve performances.
7. Completion -- like pthread condition. init_completion/DECLARE_COMPLETION/wait_for_completion/complete/complete_all
8. Spinlock - not waiting but always trying with a light loop. spin_lock_init/spin_lock/spin_unlock
   一旦kernel code得到了一个spinlock,此时preemption就会被disable。原因就是前面介绍的,如果此时取得了该spinlock的线程被抢占的话,那么有可能其他等待该spinlock的线程就会长期等待,甚至一直等待,如果被抢占的线程一直得不到执行的话。和semaphore不一样,如果一个线程得不到semaphore的话,该线程就sleep了。而当一个线程得不到spinlock的时候,该线程会tight loop轮询,这会消耗很多CPU,同时也带来了一种可能:得到spinlock的线程得到CPU的机会大大降低了。
   所以kernel要求使用spinlock的线程在得到spinlock之后不能执行任何可能会sleep的操作。但是sleep的操作非常的多,比如:从userspace读取内容或是写内容到userspace。userspace的这块内存可能被swap到了磁盘上,那么一读取磁盘线程就可能sleep直到disk I/O结束;kmalloc分配内存也可能导致线程sleep,因为当内存不够时,kmalloc会等待。
   所以,当得到了spinlock之后,之后的代码书写要非常的小心。
   
   又一种常见的锁死场景:我们的线程得到了一个spinlock,开始执行,同时中断产生。中断处理代码中也要取得这个spinlock,但是该lock不能用,于是spin。这样我们的线程就得不到执行,spinlock得不到释放,于是锁死。于是,使用spinlock的第二个注意点来了:在取得spinlock之后,disable中断。如果中断要使用和我们一样的spinlock的话。
   
   第三个注意点:在取得spinlock之后,代码的执行时间要尽可能的短,然后就释放。
9. Atomic operations. atomic_t type/atomic_add/atomic_inc/atomic_dec...
10. Read-Copy-Update operation.

==================================================================================================
Chapter 6: Advanced Char Driver Operations
1.

转载于:https://www.cnblogs.com/super119/archive/2012/01/09/2317309.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
(英文版 第三版 中文书签我自己做的 大家要是不喜欢就用福听PDF删除掉我加上去的东西 我还有很多好资源 大家都去逛逛 还有这个是单本的 网上还有个分很多章的) 前言 1 第一章 设备驱动程序简介 9 设备驱动程序的作用 10 内核功能划分 12 设备和模块的分类 14 安全问题 15 版本编号 17 许可证条款 18 加入内核开发社团 19 本书概要 19 第二章 构造和运行模块 21 设置测试系统 21 Hello World模块 22 核心模块与应用程序的对比 24 编译和装载 28 内核符号表 33 预备知识 35 初始化和关闭 36 模块参数 40 在用户空间编写驱动程序 42 .快速参考 44 第三章 字符设备驱动程序 46 scull的设计 46 主设备号和次设备号 47 一些重要的数据结构 53 字符设备的注册 59 open和release 62 scull的内存使用 64 read和write 67 试试新设备 74 快速参考 74 第四章 调试技术 76 内核中的调试支持 76 通过打印调试 78 通过查询调试 85 通过监视调试 94 调试系统故障 96 调试器和相关工具 102 第五章 并发和竞态 109 scull的缺陷 109 并发及其管理 110 信号量和互斥体 111 completion 116 自旋锁 118 锁陷阱 123 除了锁之外的办法 125 快速参考 132 第六章 高级字符驱动程序操作 137 ioctl 137 阻塞型I/O 149 poll和select 163 异步通知 168 定位设备 172 设备文件的访问控制 173 快速参考 179 第七章 时间、延迟及延缓操作 183 度量时间差 183 获取当前时间 188 延迟执行 190 内核定时器 196 tasklet 202 工作队列 204 快速参考 208 第八章 分配内存 213 kmalloc函数的内幕 213 后备高速缓存 217 get_free_page和相关函数 221 vmalloc及其辅助函数 225 per-CPU变量 228 获取大的缓冲区 230 快速参考 231 第九章 与硬件通信 235 I/O端口和I/O内存 235 使用I/O端口 239 I/O端口示例 245 使用I/O内存 248 快速参考 254 第十章 中断处理 258 准备并口 259 安装中断处理例程 259 实现中断处理例程 269 顶半部和底半部 274 中断共享 278 中断驱动的I/O 281 快速参考 285 第十一章 内核的数据类型 287 使用标准C语言类型 287 为数据项分配确定的空间大小 289 接口特定的类型 289 其他有关移植性的问题 291 链表 294 快速参考 298 第十二章 PCI驱动程序 300 PCI接口 300 ISA回顾 317 PC/104和PC/104+ 319 其他的PC总线 319 SBus 320 NuBus 321 外部总线 321 快速参考 322 第十三章 USB驱动程序 324 USB设备基础 326 USB和Sysfs 329 USB urb 331 编写USB驱动程序 342 不使用urb的USB传输 352 快速参考 356 第十四章 Linux设备模型 359 kobject、kset和子系统 361 低层sysfs操作 368 热插拔事件的产生 372 总线、设备和驱动程序 374 类 384 各环节的整合 388 热插拔 394 处理固件 401 快速索引 403 第十五章 内存映射和DMA 408 Linux的内存管理 408 mmap设备操作 418 执行直接I/O访问 429 直接内存访问 435 快速参考 453 第十六章 块设备驱动程序 458 注册 459 块设备操作 464 请求处理 468 其他一些细节 484 快速参考 487 第十七章 网络驱动程序 491 snull设计 492 连接到内核 495 net_device结构细节 499 打开和关闭 508 数据包传输 510 数据包的接收 514 中断处理例程 516 不使用接收中断 518 链路状态的改变 521 套接字缓冲区 521 MAC 地址解析 525 定制 ioctl 命令 527 统计信息 528 组播 529 其他知识点详解 533 快速参考 534 第十八章 TTY驱动
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值