[1]
http://opencsl.openfoundry.org/Lab06_interrupt_exception.rst.html
[2]
http://blog.csdn.net/wavemcu/article/details/8577058
[3]
http://blog.xuite.net/ian11832/blogg/29210698-%E5%9C%A8+linux+%E4%B8%AD%E6%96%B0%E5%A2%9E%E8%87%AA%E5%B7%B1%E7%9A%84system+call+%28%E5%AF%A6%E5%81%9A%E5%9C%A8ARM+%E5%B9%B3%E5%8F%B0%E4%B8%8A%29
[4]
http://blog.csdn.net/adaptiver/article/details/7175165
3.1 system call 的撰寫方法
要新增 system call 除了撰寫程式本身之外,還需要向 Linux 註冊讓 kernel 知道它的存在 ,這樣 user program 才能夠透過 kernel 呼叫 system call。註冊 system call 的步驟如下:
- 註冊 system call 的名字
- 定義新 system call 的代碼
- 調整 Makefile ,使 systam call 被包含在 kernel 中
- 增加 system call 的 header file ,讓 user program 能夠 include
- 使用 printk 而不是 print
- 使用 kmalloc、kfree 而不是 malloc、free
3.2 加入自己的 system call
在本節中,我們將透過 3.1 所敘述的步驟自己在系統中新增一個 system call ,這個 system call 將會顯示開機後它總共被呼叫了幾次。- 撰寫 system call 的程式system call 的程式是放在 <linux>/arch/arm/kernel 中,檔名即為 system call 的名字。
用編輯器打開 mysyscall.c 後,將以下內容複製進去:
#include <linux/linkage.h> // asmlinkage #include <linux/kernel.h> // linux/printk.h #include <linux/types.h> // atomic_t #include <linux/atomic.h> // atomic_inc() asmlinkage void sys_mysyscall(void) { static atomic_t count = ATOMIC_INIT(0); atomic_inc(&count); printk("mysyscall has been called for %d time(s)\n", count); }
header檔linux/kernel.h引用linux/printk.h中包含了printk的log層級:
- 註冊 system call 的名字<linux>/arch/arm/kernel/call.S 定義了系統中 system call 的名字,我們要將新的 system call 紀錄在這個檔案中。請用編輯器打開 call.S 之後,找到目前的最後一個 system call,
CALL(sys_get_mempolicy) CALL(sys_set_mempolicy)
然後在後面加上
CALL(sys_mysyscall)
再存檔即可。
- 定義新 system call 的代碼<linux>/include/asm-arm/unistd.h 定義了系統中 system call 的代碼,我們也需要在這裡定義新的 system call 代碼。請用編輯器打開 unistd.h 後,找到目前的最後一個 system call(大約在350行),
#define __NR_get_mempolicy (__NR_SYSCALL_BASE+320) #define __NR_set_mempolicy (__NR_SYSCALL_BASE+321)
然後在後面加上
#define __NR_mysyscall (__NR_SYSCALL_BASE+322)
- 調整 Makefile ,使 systam call 被包含在 kernel 中<linux>/arch/arm/kernel/Makefile 是該目錄的 makefile ,我們要將 mysyscall.c 加入編譯的範圍內。在檔案一開頭可以找到需要編譯的 object file 列表,
obj-y := compat.o entry-armv.o .....
#define KERN_EMERG "<0>" /* system is unusable */ #define KERN_ALERT "<1>" /* action must be taken immediately */ #define KERN_CRIT "<2>" /* critical conditions */ #define KERN_ERR "<3>" /* error conditions */ #define KERN_WARNING "<4>" /* warning conditions */ #define KERN_NOTICE "<5>" /* normal but significant */ #define KERN_INFO "<6>" /* informational */ #define KERN_DEBUG "<7>" /* debug-level messages */所以 printk() 可以這樣用:printk(KERN_INFO "Hello, world!\n");。
log層級太低訊息只會顯示在dmesg指令執行時,在commandline不會顯示任何訊息
- 增加 system call 的 header file ,讓 user program 能夠 include接著,我們要將 mysyscall 的 header 加入 linux 的 header 目錄中,它的位置是 <linux>/include/linux ,在該目錄裡新增 mysyscall.h 的檔案,並填入以下內容:
#include <linux/unistd.h> #define __NR_mysyscall (__NR_SYSCALL_BASE+322) #define mysyscall(void) syscall(__NR_mysyscall);
再存檔即可。
- 重新編譯 kernel最後,回到 <linux> 並鍵入
make CROSS_COMPILE=arm-linux-uclibc- ARCH=arm
重新編譯 kernel 後,就會產生新的 kernel image 了。
3.3 用 QEMU 測試
為了測試 system call 是否有成功加到 kernel 中,我們可以先用 QEMU 載入新的 kernel image ,並另外寫一個 user program 來呼叫 mysyscall 。- 撰寫 user program若要呼叫 mysyscall ,要在程式中 include linux/mysyscall.h 。以下為使用 mysyscall 的範例:
#include "linux/mysyscall.h" int main(){ mysyscall(); return 0; }
- 編譯程式
在寫好程式之後,我們可以用之前做好的 cross-compiler 來編譯程式,不過要注意的一點是,因為程式的內容牽涉到 kernel 的資訊( system call 是包含在 kernel 中的 ),因此我們也需要加入 kernel 的 include 檔。
假設要編譯的程式檔名為 test.c ,而要生成的執行檔為 test.out ,則在終端機下鍵入:
arm-linux-uclibc-gcc -I<linux>/include/ -static test.c -o test.out即可。