1 環境准備
運行系統:vmware下安裝的ubuntu10.10 32bit桌面版。
編譯內核版本: linux-2.6.32.63
內核目錄: /home/wanchouchou/linuxKernel/linux-2.6.32.63
為了方便,使用chmod 777 -R linux-2.6.32.63/ 將所有的內核文件都改為全權限,這樣就可以在非root狀態修改文件進行編譯了。
2 添加系統調用
首先進入linux-2.6.32.63目錄下。以后的文件路徑都是以此目錄為“根目錄”的。
2.1 在系統函數表中添加表項
進入arch/x86/kernel目錄下,然后vim syscall_table_32.S,在此文件的最后一行添加自己的系統調用表項:
1 .long sys_rt_tgsigqueueinfo /* 335 */ 2 .long sys_perf_event_open 3 .long sys_mycall //這是我們自己添加的表項
好了,下面開始添加系統調用號。
2.2 添加自己的系統調用號
現在進入目錄 arch/x86/include/asm,該目錄下有三個文件unistd_32.h, unistd_64.h, unistd.h。由於我們編譯的是32位內核,所以需要在unistd_32.h中添加系統調用號。
vim unistd_32.h,在最后添加代碼:
1 #define __NR_perf_event_open 336 2 #define __NR_mycall 337 //添加的 3 #ifdef __KERNEL__ 4 5 /* 原本為337,但是由於我們添加了一行,所以改338*/ 6 #define NR_syscalls 338
2.3 編寫自己系統調用的實現函數
由於系統調用必須編譯到核心的內核鏡像中去。所以我們將此函數的實現寫到kernel/sys_i386_32.c中:
1 //引入頭文件 2 #include <asm/page.h> 3 ........ 4 //添加函數代碼 5 asmlinkage long sys_mycall(void){ 6 return THREAD_SIZE; 7 }
3 編譯內核
現在就可以回到linux-2.6.32.63目錄進行編譯了。如果以前編譯過內核,最好使用make mrproper和make clean命令來清除之前的編譯殘留文件。如果是第一次編譯內核,那么就需要對內核的編譯選項進行配置,這里推薦使用make menuconfig。如果鍵入該命令后提示缺少ncurses庫文件的話,就使用sudo apt-get install libncurses5-dev命令安裝該庫。之后就可以進行menuconfig配置了,建議保持默認值即可。
一切准備就緒,鍵入make命令開始編譯內核!現在可以泡一桶coffee來慢慢喝了,為什么是一桶?因為時間真的很長~~~
4 編譯並安裝內核模塊
make modules ,這個相對來說要快一點。10分鍾左右。然后安裝內核模塊: make modules_install 以及安裝內核: make install
5 讓新舊內核均可以加載
sudo mkinitramfs -o /book/initrd.img-2.6.32.63 //此命令會在/boot目錄下生成initrd.img-2.6.32.63等文件
sudo update-initramfs -c -k 2.6.32.63 //根據/lib/modules/2.6.32.63文件進行更新。如果此命令出現FATAL: could not load /lib/modules/2.6.32.63的話,就將命令后面的2.6.32.63改為此目錄下的新內核文件名即可(注意:舊內核文件名為2.6.35-22-generic)。
sudo update-grub2 //自動修改系統的引導配置文件,主要是更新/book/grup/grup.cfg啟動文件。此命令執行完后會在grup.cfg中添加新內核的啟動項
6 進入grup選擇需要啟動的內核
在ubuntu10.10默認grup菜單是不會顯示的,也就是說無法選擇啟動的內核。要想顯示的話,需要按照如下步驟進行操作:
1、把/etc/default/grub文件中的GRUB_HIDDEN_TIMEOUT=0改為大於0的數字,比如4;
2、把/etc/grub.d/30_os-prober文件中所有的set timeout=0中的0改為10.仔細找,不要漏過了;
3、上述修改完成后,執行命令更新grup2: sudo update-grub //更新/boot/grub/grub.cfg文件
7 重啟
reboot。這時候在啟動的時候就會停留在grup界面了,里面有4個選項,每個內核對應2個,選擇進入2.6.32.63內核。啟動完成后在終端輸入: uname -a 顯示的就是新內核版本了。
8 驗證自定義的系統調用
現在我們可以編寫代碼來驗證自定義的系統調用是否被加入到了內核中:
1 #include<sdtio.h> 2 #include<unistd.h> 3 #include<sys/syscall.h> 4 5 #define SYS_mycall 337 //同我們前面定義的系統調用號相同 6 7 int main(){ 8 long ret = 0; 9 ret = syscall(SYS_mycall); //根據系統調用號調用對應的系統調用 10 printf("ThreadSize is: %ld\n", ret); 11 return 0; 12 }
需要說明的是,在2.6.20以后的版本是沒有以前的那些系統調用宏定義的(如_syscall0, _syscall1等),必須使用syscall來進行系統調用(可以通過man syscall獲取參考信息)。同時由於是系統調用,所以需要root模式下編譯、運行程序。程序運行結果: 8192。
注意,按理來說,我們是不需要自己定義SYS_mycall = 337的,但是,如果不這樣的話編譯的時候會提示找不到SYS_mycall,也就是說,它並沒有被顯示地加入到syscall.h文件中~解決辦法如下:
1、修改/usr/include/asm/unistd_32.h文件,將最后的#define __NR_recvmmsg 337 改為 #define __NR_mycall 337 //貌似系統中根本就沒有recvmmsg只有recvmsg~
2、修改/usr/include/bits/syscall.h文件,在文件開頭位置加入代碼: #define SYS_mycall __NR_mycall ;
這樣,我們就可以直接在程序中使用SYS_mycall了。
