如何實現乙個新的linux系統呼叫

2021-06-20 12:54:27 字數 3429 閱讀 7445

摘自【linux核心修煉之道 第五章】

為 linux 新增新的系統呼叫是件相對容易的事情,主要包括有 4 個步驟:編寫系統呼叫服務例程;添

加系統呼叫號;修改系統呼叫表;重新編譯核心並測試新新增的系統呼叫。

下面以乙個並無實際用處的 hello 系統呼叫為例,來演示上述幾個步驟。

(1)編寫系統呼叫服務例程。

遵循前面所述的幾個原則,hello 系統呼叫的服務例程實現為:

01 asmlinkage long sys_hello(void)

02

通常,應該為新的系統呼叫服務例程建立乙個新的檔案進行存放,

但也可以將其定義在其他檔案之中並加

上注釋做必要說明。同時,還要在 include/linux/syscalls.h 檔案中新增原型宣告:

asmlinkage long sys_hello(void);

sys_hello 函式非常簡單,僅僅列印一條語句,並沒有使用任何引數。如果我們希望 hello 系統呼叫不

僅能列印「hello!」歡迎資訊,還能夠列印出我們傳遞過去的名稱,或者其他的一些描述資訊,則 sys_hello

函式可以實現為:

01 asmlinkage long sys_hello(const char __user *_name)

02 11

12 printk(「hello, %s!\n」, name);

13 return 0;

14 error:

15return ret;

}

第二個 sys_hello 函式使用了乙個引數,在這種有引數傳遞發生的情況下,編寫系統呼叫服務例程時必

須仔細檢查所有的引數是否合法有效。因為系統呼叫在核心空間執行,如果不加限制任由使用者應用傳遞輸

入進入核心,則系統的安全與穩定將受到影響。

引數檢查中最重要的一項就是檢查使用者應用提供的使用者空間指標是否有效。

比如上述 sys_hello 函式參

數為 char 型別指標,並且使用了__user 標記進行修飾。__user 標記表示所修飾的指標為使用者空間指標,不

能在核心空間直接引用,原因主要如下。

使用者空間指標在核心空間可能是無效的。

使用者空間的記憶體是分頁的,可能引起頁錯誤。

如果直接引用能夠成功,就相當於使用者空間可以直接訪問核心空間,產生安全問題。

因此,為了能夠完成必須的檢查,以及在使用者空間和核心空間之間安全地傳送資料,就需要使用核心

提供的函式。比如在 sys_hello 函式的第 6 行,就使用了核心提供的 strndup_user 函式(在 mm/util.c 檔案中

定義)從使用者空間複製字串 name 的內容。

(2)新增系統呼叫號。

每個系統呼叫都會擁有乙個獨一無二的系統呼叫號,所以接下來需要更新 include/asm-i386/unistd.h 文

件,為 hello 系統呼叫新增乙個系統呼叫號。

328 #define __nr_utimensat

320329 #define __nr_signalfd

321330 #define __nr_timerfd 322

331 #define __nr_eventfd 323

332 #define __nr_fallocate 324

333 #define __nr_hello 325 /*分配 hello 系統呼叫號為 325*/

334335 #ifdef __kernel__

336337 #define nr_syscalls 326 /*將系統呼叫數目加 1 修改為 326*/

(3)修改系統呼叫表。

為了讓系統呼叫處理程式 system_call 函式能夠找到 hello 系統呼叫,我們還需要修改系統呼叫表

sys_call_table,放入服務例程 sys_hello 函式的位址。

322 .long sys_utimensat

/* 320 */

323 .long sys_signalfd

324 .long sys_timerfd

325 .long sys_eventfd

326 .long sys_fallocate

327 .long sys_hello /*hello 系統呼叫服務例程*/

新的系統呼叫 hello 的服務例程被新增到了 sys_call_table 的末尾。我們可以注意到,sys_call_table 每

隔 5 個表項就會有乙個注釋,表明該項的系統呼叫號,這個好習慣可以在查詢系統呼叫對應的系統呼叫號

時提供方便。

(4)重新編譯核心並測試。

為了能夠使用新新增的系統呼叫,需要重新編譯核心,並使用新核心重新引導系統。然後,我們還需

要編寫測試程式對新的系統呼叫進行測試。針對 hello 系統呼叫的測試程式如下:

00 #include 01 #include 02 #include 03

04 #define __nr_hello

32505

06 int main(int argc, char *argv)

07

然後使用 gcc 編譯並執行:

$gcc –o hello hello.c

$./hello

hello!

由執行結果可見,系統呼叫新增成功。

什麼時候需要新增新的系統呼叫

雖說新增乙個新的系統呼叫非常簡單,但這並不意味著使用者有必要這麼做。新增系統呼叫需要修改內

核源**、重新編譯核心,如果更進一步希望自己新增的系統呼叫能夠得到廣泛的應用,就需要得到官方

的認可並分配乙個固定的系統呼叫號,還需要將該系統呼叫在每個需要支援的體系結構上實現。因此我們

最好使用其他替代方法和核心交換資訊,如下所示。

使用裝置驅動程式。建立乙個裝置節點,通過 read 和 write 函式進行讀寫訪問,使用 ioctl 函式進行設

置操作和獲取特定資訊。

這種方法最大的好處在於可以模組式載入解除安裝,

避免了編譯核心等過程,

而且呼叫介面固定,容易操作。

使用 proc 虛擬檔案系統。利用 proc 介面獲取系統執行資訊和修訂系統狀態是一種很常見的手段,比

如讀取/proc/cpuinfo 可以獲得當前系統的 cpu 資訊,

通過裝置驅動提供的 proc 介面還可以設定硬

件暫存器。

sysfs 檔案系統。sysfs 檔案系統在 2.6 核心被引入,是乙個類似於 proc 檔案系統的特殊檔案系統,用於對

系統的裝置進行管理,它把實際連線到系統上的裝置和匯流排組織成層次結構,並向使用者提供詳細的核心數

據結構資訊,使用者可以利用這些資訊以實現和核心的互動

如何實現乙個UI系統

如何為我的遊戲實現乙個ui系統,這個問題我想了很久,不過我現在可不像開始的時候那樣一點思路也沒有。如果你也被這個問題所困擾,我十分樂意與你分享這幾天來的學習成果。嘿嘿,我是不是有點得意忘形了?在開始之前,我要提醒你,學而不思則惘。在看這篇文章的時候,請時刻保持頭腦清醒,如果有什麼不太明白的話,請停下...

面對乙個新的系統

1 檢查linux系統 如果您是剛剛接手了一台linux系統,請先確認這台系統是不是紅帽rhel7系統再進行下面的操作哦 root localhost cat etc redhat release red hat enterprise linux server release 6.5 santiag...

如何實現乙個檔案系統(六)

1 1 請參見 operation systems internals and design principles 一書第12章 2 2 扇區是磁碟的最小定址單元,而檔案塊是核心操作檔案的最小單位,乙個塊可以包含乙個或數個扇區。這些磁碟塊被讀入記憶體後即刻被存入緩衝中,同樣,檔案塊被寫出也要通過緩衝...