Linux device drivers 3rd Edition reading notes

來源:互聯網
上載者:User
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.

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.