編譯安裝 Linux 4.2.6 內核
實驗環境
阿里云服務器 Centos_7_03 64 位
本次實驗使用最基本的方法對內核進行編譯安裝,所有操作均在 root 用戶權限下施行??墒褂?su 命令切換到 root 權限。
環境準備
1.準備 Linux 4.2.6 源碼:
可以在官網 http://www.kernel.org 上下載,這里我們下載4.2.6版本。
不過阿里提供了 http://mirrors.aliyun.com ,也可以在這里面下載,速度更快。下載鏡像的命令如下:
cd /tmp
wget http://mirrors.aliyun.com/linux-kernel/v4.x/linux-4.2.6.tar.xz
2.準備安裝需要的環境:
更新軟件源
yum update
安裝需要的環境
xz -d linux-4.2.6.tar.xz
tar –xvf linux-4.2.6.tar
把內核目錄 Linux-4.2.6 復制到 /usr/src 目錄下,并進入 /usr/src
準備編譯
如圖所示,當前系統內核版本為 3.10.0-693.5.2.el7.x86_64,進入之前內核的文件目錄,拷貝 .config 文件到 Linux-4.2.6 目錄中。
進入 Linux-4.2.6 目錄,然后執行 make menuconfig 指令.
在配置界面,選擇 64bits-kernel 的配置文件為我們剛剛復制的 .config 文件。
編譯內核
1.編譯啟動鏡像
make bzImage -j2
值得一提的是這里的 -j2 參數,表示的是 CPU 數目*2,由于我的阿里云服務器是單核的,所以是 -j2,如果是雙核服務器則可以改為 -j4。
當然,直接使用 make bzImage 也可以直接編譯
2.編譯模塊
make modules -j2
同樣,也可以直接執行 make modules
編譯的過程比較的緩慢,如果是正常的 ubuntu 系統可能會用上1-2小時,而輕量級的阿里云主機需要花上半小時左右的時間。
安裝內核
先安裝模塊: make modules_install
在安裝內核: make install
更改啟動的內核引導順序
CentOS 7 系統使用 grub2 作為引導程序,需進行如下操作:
1.查看系統內部有多少個內核:
cat /boot/grub2/grub.cfg |grep menuentry
2.配置從默認內核啟動,下面命令的內核名稱根據系統內部查到的實際名稱來替換:
grub2-set-default 'Linux 4.2.6 7 (Core)'
3.驗證是否配置成功:
grub2-editenv list
驗證結果
現在,重新啟動服務器,再次查看服務器的內核版本號:
系統版本已經是 linux 4.2.6
添加系統調用
實驗流程
- 在下載的 4.2.6 內核中添加一個 hellosys 系統調用,其功能為打印一條由調用者傳入的一行字符串;
- 重新編譯、安裝內核;
- 編寫用戶測試程序,測試 hellosys 系統調用。
分配系統調用號
先去查看一下系統的調用號使用到多少了, 查找一下系統調用表
/usr/src/linux-4.2.6/arch/x86/entry/syscalls/syscall_64.tbl
我的版本使用到了322, 所以我新的系統調用用323號。注意文件里要看屬于x64的系統調用號。
然后我們修改 /usr/include/asm-generic/unistd.h
設置系統調用號,添加系統調用并修改系統調用的總數
修改系統調用表
修改系統調用表 /usr/src/linux-4.2.6/arch/x86/entry/syscalls/syscall_64.tbl
關聯調用號與調用的服務例程地址
編寫調用程序
在 /usr/src/linux-4.2.6/include/linux/syscalls.h
中添加一個函數聲明
asmlinkage long sys_hellosys(long uid, const char __user *content);
打開 /usr/src/linux-4.2.6/kernel/sys.c
并在結尾添加這段函數
asmlinkage long sys_hellosys(long uid, const char __user *content){
printk("%d wants to say hello, and %s", uid, content);
return 1;
}
確認保存函數的聲明、實現,按照上文所述重新編譯安裝內核映像。
使用系統調用
測試程序:
#include <sys/syscall.h>
#include <stdio.h>
#include <unistd.h>
int main(){
long ret = syscall(323, 100, "this is a new system call!");
//syscall 參數1 調用號 之后為系統調用的參數列表
printf("result is %ld\n", ret);
return 0;
}
編譯、執行 test.c,并查看內核輸出的信息
g++ test.c -o test
./test
dmesg | grep "hello"
內核輸出信息,說明系統調用成功的獲取了用戶的信息。