使用ioctl「實現」自定義的系統呼叫

2022-05-10 19:22:21 字數 1760 閱讀 1661

最近做的專案跟linux核心的關係比較大,我們的專案需要在使用者態觸發一些核心態的**執行。眾所周知,核心態的**是不能直接被使用者態**呼叫的,使用者態**觸發核心態**的必須要經過系統呼叫。

那麼該如何實現我們的需求呢?有幾種方法:

改寫核心,擴大系統呼叫表,新增新的系統呼叫

利用核心模組,覆蓋沒被使用或這使用頻率很低的乙個系統呼叫的處理函式

利用已有的系統呼叫,比如ioctl,來「實現」自定義的系統呼叫。

第一種方法需要修改核心,適用面比較窄;第二種方法hack意味很濃,沒有被使用的系統呼叫號有限,不同模組可能都使用這種機制,可能會產生衝突。最終我們選擇了第三種方法。下面將一一道來。

ioctl系統呼叫是使用者態控制裝置的介面,其使用者態原型為

int ioctl(int d, int request, ...)

第乙個引數是開啟的裝置檔案的檔案描述符,通常是open系統呼叫的返回值;第二個引數request是可以自定義的請求號;第三個引數可以是乙個指 針,指向一段使用者態記憶體,用來傳遞引數,也可以是乙個整形資料。函式原型中的'...'並非表示ioctl是可變引數函式,只是為了告訴編譯器不要檢查第 三個引數。

在較新核心中,ioctl的核心態原型為unlock_ioctl

long unlocked_ioctl(struct file *file, unsigned int request, unsigned long arg);

這個原型可以在struct file_operation的定義中找到,還有乙個compat_ioctl,用於核心為64位,使用者空間為32位的情形,跟我們的需求關係不大。

傳入的request和arg就來自於ioctl系統呼叫的第二個和第三個引數。在核心態中,可以根據request的值,來呼叫約定的函式,「實現」自定義的系統呼叫。

需要注意的是,request的值並不是可以隨隨便便自定義的,需要遵循一些規則,可以參考《選擇ioctl命令》(注意它用的ioctl的原型是老核心的)。

ioctl是用來操作裝置的,因此我們需要乙個虛擬的裝置,以便ioctl能夠工作。

實現虛擬裝置需要通過核心模組來實現。這篇文章寫了如何寫乙個入門的核心模組。

在核心模組初始化**中

用alloc_chrdev_region申請乙個裝置號

初始化乙個struct file_operations型別的全域性變數,將open、close、unlocked_ioctl等成員賦值為我們實現的函式。

利用cdev_add將裝置號與file_operations關聯起來

用class_create建立乙個裝置類

用device_create建立乙個虛擬裝置

在核心模組銷毀**中

用cdev_del解除裝置號與裝置操作之間的關聯

用device_destroy銷毀裝置

用class_destroy銷毀裝置類

用unregister_chrdev_region釋放裝置號。

在自定義的unlocked_ioctl中

通過switch-case,根據request號進入某個case

如果目標函式沒有引數,那麼直接呼叫即可

如果要傳遞給目標函式的引數直接儲存在arg中,則直接讀取arg再呼叫即可。

如果要傳遞給目標函式的引數是arg所指向的一段使用者態記憶體,則需要從使用者態拷貝到核心態。較少的資料可以用get_user和put_user來讀寫,較多的資料可以用copy_from_user和copy_to_user來讀寫。準備好引數之後,呼叫目標函式

自定義Toast實現自定義Toast布局

平時我們使用toast的時候都是這樣的一種方法 toast toast toast.maketext context,duration 現在我們來自定義下toast的布局,首先看下toast建立時的源 public static toast maketext context context,char...

自定義View的實現

自定義view分為三種型別 0 繼承現有的ui控制項 實現特定功能,例如事件攔截,就像是我的slidingpanelayout和viewpager結合 自定義view 0 繼承現有的控制項 1 將多個控制項進行組合,形成新的自定義view radio動態指示器,radiobutton的自定義?自定義...

實現自定義IFormattable

using system using system.collections using system.linq using system.text using system.collections.generic using system.runtime.serialization namespac...