如何往核心中新增自己寫的系統呼叫?其實步驟非常簡單:
1.編寫乙個系統呼叫;
2.在系統呼叫表末尾加入乙個新表項;
3.在< asm/unistd.h >中新增乙個新的系統呼叫號;
4.重新編譯核心;
上述工作完成後,就可以在使用者程式中使用自己所編寫的系統呼叫了。接下來,我們將逐步分析如何上述步驟。
1.編寫系統呼叫
我們將要實現乙個獲得當前程序pid的的系統呼叫。對於乙個程序,我們可以直接通過current->pid來獲得。為了使得這個系統呼叫同樣適用於乙個執行緒,我們使用current->tgid。這麼做的原因是同乙個執行緒組內的所有執行緒tgid均相同;而乙個程序的pid和tgid是相同的。
view source
print?
1
asmlinkage
long
sys_mygetpid(
void
)
2
與普通函式不同的是,這個系統呼叫的函式名前有asmlinkage修飾符。這個修飾符使得gcc編譯器從堆疊中取該函式的引數而不是暫存器中。另外,系統呼叫函式的命名規則都是sys_***的形式。
接下來,我們的要做的是將這個函式放於何處。一種方法是,將上述函式放於/kernel/下的某個檔案中;另一種方式是,將這個函式單獨存放在/kernel/下的乙個新建的.c檔案中。不管何種方法,所做的目的都是為了在重新編譯核心時將上述我們所編寫的系統呼叫函式編譯進核心。
2.在系統呼叫表中新增新的表項
linux中為每乙個系統呼叫都分配乙個系統呼叫號。也就是說,每乙個系統呼叫號都唯一的對應著乙個系統呼叫。核心中使用系統呼叫表來記錄所有已經註冊過的系統呼叫,這個系統呼叫表儲存在sys_call_table中。在yoursource/arch/x86/kernel/syscall_table_32.s中可以看到系統系統呼叫表。
我們所要做的就是在該錶的末尾新增我們剛編寫的系統呼叫:.long sys_getpid。我們並不需要顯式的指定系統呼叫號,從0開始算起,我們所編寫的函式的系統呼叫號為341。
view source
print?
01
entry(sys_call_table)
02
.
long
sys_restart_syscall
/* 0 - old "setup()" system call, used for restarting */
03
.
long
sys_exit
04
.
long
ptregs_fork
05
.
long
sys_read
06
.
long
sys_write
07
.
long
sys_open
/* 5 */
08
…… ……
09
.
long
sys_perf_event_open
10
.
long
sys_recvmmsg
11
.
long
sys_fanotify_init
12
.
long
sys_fanotify_mark
13
.
long
sys_prlimit64
/* 340 */
14
.
long
sys_mygetpid
3.在< asm/unistd.h >中新增乙個新的系統呼叫號
上一步,在系統呼叫表中新增新的表項是為了將系統呼叫號和系統呼叫關聯起來。現在,我們需要在unistd.h檔案中新增具體的系統呼叫號,這樣使得系統可以根據這個系統呼叫號在系統呼叫表中查詢具體的系統呼叫。
當使用者程序呼叫乙個系統呼叫時,其實是通過乙個中斷號為128的軟中斷來通知核心的。此時,核心會由使用者態切換到核心態轉而去執行這個軟中斷對應的中斷處理程式。而這個中斷處理程式恰好就是系統呼叫處理程式。也就是說,任何系統呼叫都會引發cpu去執行這個系統呼叫處理程式。因此,必須通過系統呼叫號來識別不同的系統呼叫。系統呼叫號通常會儲存在eax暫存器中。
現在我們就在yoursource/arch/x86/include/asm/unistd_32.h檔案中新增新的系統呼叫號。在上一步我們所新增的sys_mygetpid系統呼叫對應的編號為341,因此我們在該檔案的末尾新增下面的語句:#define __nr_mygetpid 341。注意這裡的巨集命名規則,以__nr_開頭。
view source
print?
1
#define __nr_restart_syscall 0
2
#define __nr_exit 1
3
#define __nr_fork 2
4
#define __nr_read 3
5
#define __nr_write 4
6
…………
7
#define __nr_fanotify_mark 339
8
#define __nr_prlimit64 340
9
#define __nr_mygetpid 341
4.編譯核心
如果上述三個步驟都完成後,那麼接下來重新編譯核心即可。具體可參見這裡。
5.編寫使用者態的程式
view source
print?
1
#include < linux/unistd.h >
2
3
_syscall0(
int
,mygetpid)
4
5
int
main()
6
上述使用者程式可能與我們平日裡所寫的稍有不同。主要區別是增加了_syscall0(int,mygetpid)這個巨集。因為我們現在直接在程式中呼叫系統呼叫,而我們平時則是通過呼叫c庫中的api來間接呼叫系統呼叫。在unistd.h檔案中有_syscalln()巨集的定義,這裡的n可取0~6。n代表的是需要傳遞給系統呼叫的引數個數。由於mygetpid系統呼叫需傳遞的引數個數為0,因此選取_syscall0。另外,這組巨集的內部引數分布有如下特點:第乙個引數是系統呼叫返回值的型別,第二個引數是系統呼叫函式的名稱,接下來的引數按照系統呼叫引數的次序依次是引數型別和引數名稱。對於每個巨集來說,都有2+2*n個引數。
ok,上述方法即可以將我們自己編寫的系統呼叫函式加入到核心。
Linux 核心 驅動開發總結
總體來看,需要乙個階段性總結了,因為現在sd卡的除錯也進入了卡殼期。大概會出一系列的總結文章,主要涉及的主題在下面列出 1 開發工具 gcc gdb vim ctags 2 makefile和kconfig linux核心的配置與編譯,更好的理解模組化開發 3 除錯技術 無敵的printf等 注意整...
《Linux核心分析》期末總結及學習心得
一 學習心得 本學期通過網路課程的形式完成了linux核心的學習,這種學習方式自主性相對強,十分鍛鍊及考驗我們自身。對於linux系統的理解,linux系統中包括命令 硬體 軟體裝置 作業系統 程序等相對於核心而言,都可以歸結為具有自身特性的檔案,並各自有其用途。幾點總結 二 學習目錄 部落格總結 ...
核心開發總結 pc安裝核心
1.首先將 boot 目錄下的系統配置檔案拷貝到核心源 目錄中,重新命名為.config 2.重新進行配置,形成自己的配置檔案 make menuconfig 3.進行編譯,make bzimage 4.編譯模組,make modules 5.安裝模組,make modules install 6....