2021-08-19
關鍵字:
1、內核空間與用戶空間數據交換方式
分兩種情況:
1、需要交換的數據量較大時;
2、需要交換的數據量較小時;
第一種情況使用以下的函數:
unsigned long copy_to_user(void __user* to, const void* from, unsigned long n); unsigned long copy_from_user(void* to, const void __user* from, unsigned long n);
返回值表示成功拷貝的字節數。
第二種情況則使用以下所示的宏定義:
#include <asm/uaccess.h>
put_user(local, user);
get_user(local, user);
2、MKDEV申請的設備號與register_chrdev_region申請的設備號有什麼區別?
兩種方式所描述的“設備號”是相同的。其區別用一句話概括就是:是否得到了系統的承認。
MKDEV(ma, mi) 是一個宏定義,其作用就是將參數 major 和 minor 由兩個分散的數值組合成統一的 dev_t 類型(unsigned long)。執行此宏定義後得到的“設備號”表示你想要得到這個設備號,想向全世界聲明它屬於我,不過此時它僅僅是你單方面的聲明而已。
register_chrdev_region() 的用法通常是將 MKDEV() 出來的設備號作爲參數傳入。可以理解成是在開發者單方面聲明想獨佔某個設備號後,將此設備號交由操作系統審批。當函數返回值爲0時,表示Linux系統通過了開發者的申請,前面由 MKDEV() 出來的設備號就得到開發者以及操作系統的共同認可。
3、register_chrdev_region() 與 alloc_chrdev_region() 有什麼區別?
兩函數的原型分別如下所示:
int register_chrdev_region(dev_t from, unsigned int count, const chr* name); int alloc_chrdev_region(dev_t* dev, unsigned int baseminor, unsigned int count, const char* name);
兩個函數的目的一樣,都是從系統中得到(申請)一個專屬設備號。但前者用於“靜態申請”,而後者用於“動態申請”。
靜態申請則表示開發者爲某設備靜態指定一個設備號,直接提交給系統審批。
但設備號資源是有限的,對某些動態加載的驅動來說可能會遇到靜態指定的設備號已被佔用的情況。此時最好的解決辦法就是直接向系統申請一個可用的設備號。
4、創建內核線程
可以使用 kthread_run 宏定義來創建。其原型如下
#define kthread_run(threadfn, data, namefmt, ...)
參數 threadfn 表示用於在子線程中執行的函數名。子線程函數的原型爲:int (*threadfn)(void *data)
參數 data 表示要傳遞到子線程函數去的數據地址。
參數 namefmt 及後面的可變長度個參數用於組合成此子線程的名稱。
此宏定義返回值爲一個 struct task_struct 結構體地址。可以用 IS_ERR(ts)來判斷子線程是否成功創建。
5、內核中的內存分配
內核開發中常見的分配內存的函數有兩個:
static inline void* kmalloc(size_t size, gfp_t flags); void* vmalloc(unsigned long size);
kmalloc函數與malloc函數類似,它所分配的內存空間在物理上是地址連續型的。但是它在內核中最大隻能分配128KB的內存空間。此函數第二個參數常用的值有兩個:1、GFP_KERNEL;2、GFP_ATOMIC;分別對應於在內存不足是是否阻塞調用。
vmalloc函數分配的內存空間在虛擬地址上是連續的,但是在物理地址上卻不一定。因此此函數可用於分配大內存空間,最大可達1GB。
如果在內核開發中要涉及到頻繁的申請與釋放內存空間的,爲避免產生內存碎片,可以使用內存池技術來解決。