添加 System call(系統呼叫) 至 linux kernel (環境:Ubuntu 12.04LTS + kernel:3.13.0-32)

圖與內文無關

目錄

一.背景知識
二.實作步驟
三.Step by step
四.參考文獻

一.背景知識

1.Linux
    Linux是一種自由和開放原始碼的類UNIX作業系統。術語Linux只表示作業系統核心本身,但通常採用Linux核心來表達該意思。Linux則常用來指基於Linux核心的完整作業系統,包括GUI元件和許多其他實用工具。由於這些支援使用者空間的系統工具和庫主要由理察·斯托曼於1983年發起的GNU計劃提供,自由軟體基金會提議將該組合系統命名為GNU/Linux[7][8],但Linux不屬於GNU計劃。

2.Linux kernel
    Linux內核(英語:Linux kernel),是一種電腦作業系統內核,以C語言和組合語言寫成,符合POSIX標準,以GNU通用公眾授權條款釋出。Linux內核最早是由芬蘭駭客林納斯·托瓦茲為嘗試在自己的英特爾x86架構電腦上提供自由免費的類Unix系統而開發的。該計劃開始於1991年,林納斯·托瓦茲當時在Usenet新聞群組comp.os.minix登載貼文[7],這份著名的貼文標示著Linux內核計劃的正式開始。

3.System call (系統呼叫)
    指運行在使用者空間的程序向作業系統內核請求需要更高權限運行的服務。系統調用提供了用戶程序與作業系統之間的接口。大多數系統交互式操作需求在內核態執行。如設備IO操作或者進程間通信。

二.實作步驟

各kernel版本或是本身OS的不同,在某些地方上會有些微不,例如檔案位置,檔案名稱,或是include的標頭檔不同,這部分可能就要上網找資料去惹,另外不同的 Linux 系統之間也有可能使用不同的指令,在實作時請多留意自己的環境,本實作是以 Ubuntu 12.04LTS + kernel:3.13.0-32-generic 來執行。以下流程可供參,對於其他環境來說應該是大同小異的。

Kernel side
1. 下載 kernel source
2. 定義system call sys_hello():
3. 添加 hello 目錄至 kernel's Makefile
4. 新增新的 system call "sys_hello()" 到 system call 的 table
       5. 新增新的 system call "sys_hello()" 到 system call 的標頭檔
       6.編譯 kernel 並安裝之
User side
7. 測試時間

三.Step by step

1.下載 kernel source
sudo apt-get source linux-image-3.13.0-32-generic

之後檔案會自行解壓縮至該目錄夾底下
(查看自身所處的目錄,請輸入 pwd)

2.定義system call sys_hello(): [!這裡的名稱要與後面保持一致!]

2.1前往 剛解壓縮的資料夾

$ cd linux-lts-trusty-3.13.0

2.2創建hello資料夾

$ mkdir hello

2.3進入hello資料夾

$ cd hello

2.4創建一個名為hello.c的程式



#include <linux/kernel.h>

asmlinkage long sys_hello(void){
printk("The winter is coming\n");
return 0;
}

[!printk 會輸出內容至 kernel's log file !]


2.5 創建 "Makefile" 在hello資料夾並打上指令

$ sudo nano Makefile

加上指令


obj-y := hello.o

3. 添加 hello 目錄至 kernel's Makefile

3.1 切回到 linux-lts-trusty-3.13.0

$ cd ..

3.2 開啟 MakeFile

$ sudo nano Makefile

3.2 修改版本號(optional)

可以在Makefile中修改版本號,方便辨識
3.2 找到添加目錄的位置並將hello 資料夾放入

找到"core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/"
改成"core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ hello/"

[這裡是確保 hello.c 會被編譯並 include 到 kernel source code]



4. 新增新的 system call "sys_hello()" 到 system call 的 table

4.1若是 32 位元,請至 "linux-lts-trusty-3.13.0/arch/x86/syscalls"
修改 system_32.tbl

$ cd arch/x86/syscalls

$ sudo nano system_32.tbl

添加以下指令到文件的最後一行

355 i386 hello sys_hello

[將數字筆記下來,最後的測試會用到]
[355-指system call 的編號,這應該是由該檔案的最後個編號+1而得到]



4.2若是 64 位元,請至 "linux-lts-trusty-3.13.0/arch/x86/syscalls"
修改 system_32.tbl

$ cd arch/x86/syscalls

$ sudo nano system_64.tbl

添加以下指令到文件的最後一行

545 64 hello sys_hello

[將數字筆記下來,最後的測試會用到]
[545-指system call 的編號,這應該是由該檔案的最後個編號+1而得到]



5.新增新的 system call "sys_hello()" 到 system call 的標頭檔

5.1 切換至 linux-3.13/include/linux

$ cd ../../..

$ cd include/linux

5.2 修改標頭黨(syscalls.h)

$ sudo nano syscalls.h

5.3 添加以下指令到檔案最後

asmlinkage long sys_hello(void);



6.編譯 kernel 並安裝之 [會出錯一定是在這邊啦(挖鼻)]

6.1 前置作業

$ sudo apt-get install gcc
$ sudo apt-get install libncurses5-dev
$ sudo apt-get update
$ sudo apt-get upgrade

6.2 開始預編譯 kernel 設定畫面

$ sudo make menuconfig

[跳出個復古的畫面(Generation Gap 出現...)後,只需要確定 ext4 有被勾選即可]



6.3 創建 DEB 檔案

$ sudo make -j 5 KDEB_PKGVERSION=1.任意-文字-於此地 deb-pkg

創建出來的 *.DEB 會出現在前個資料夾底下

6.4 打兩場 LOL || 自已泡&喝咖啡 || 慢跑 20 圈再回來

6.5 確定編譯沒有出錯
可能出現的問題
a.剛剛的 hello.c code 打錯
b.sys_hello 在某個環節打錯
c.標頭檔沒有增加
d.套件太久或是缺少套件
e.沒放乖乖在電腦上

(我好像花了 1.5 hr 在這邊)

6.6 編譯成功QQ



6.7 安裝方才的 *.deb 檔案

$ cd ..

$ sudo dpkg -i linux*.deb

[這會安裝剛剛自行編譯的 kernel 到系統上]



6.8 檢查現在的 kernel 版本號

$ uname -r

6.9 重新開機

$ sudo reboot

7. 測試時間

7.1 確認 kernel 是否安裝成功

$ uname -r



7.2 編寫一段引用system call的 code



7.3 編譯並執行之

$ gcc -g -Wall yourCodeName.c -o anyName

$ ./anyName

7.4 檢查是否成功

如果成功的話你會看到

"System call sys_hello returned 0" 顯示在終端機上



如果失敗的話你會看到

"System call sys_hello returned -1" 顯示在終端機上

7.5 看輸出結果

$ dmesg

這將會顯示 "The winter is coming" 在終端機的最後面


7.6 測試影片



四.參考文獻

1.http://www.franksthinktank.com/howto/addsyscall/
2.https://arvindsraj.wordpress.com/2012/10/05/adding-hello-world-system-call-to-linux/
3.https://tssurya.wordpress.com/2014/08/19/adding-a-hello-world-system-call-to-linux-kernel-3-16-0/
4.http://stackoverflow.com/questions/26720644/adding-new-system-call-to-linux-kernel-3-13-on-64-bit-system
5.http://linux.vbird.org/linux_basic/redhat6.1/linux_10kernel.php

留言

  1. 真的很感謝你的文章,
    提供很完善的說明,
    對於學習真的很有幫助
    另外在hello.c的部份
    上面的include好像打錯摟><
    謝謝你~~

    回覆刪除
    回覆
    1. 感謝的你幫忙XD
      等等就把這個手誤修正回來:-p

      刪除
  2. 不好意思 想跟大大請教一下
    在步驟4.1的部分 如果打開tbl裡面是空的這正常嗎@@?
    (系統是新灌的,除了寫syscall沒做其他事)

    回覆刪除
  3. 不正常,那邊的時候檔案應該會如圖所示
    有編號,有內容
    檢查看看是不是檔案看錯,或是正在操作的作業系統
    所存放的檔案位置在其他地方或名稱有所改變
    加油:-)

    回覆刪除
  4. 不好意思,6.3有更詳細的說明嗎?新手有好多不太會XD"
    一直無法執行sudo -j 5 KDEB_PKGVERSION=1.任意-文字-於此地 deb-pkg
    是要在特定的位置?(linux/底下)sudo -j 顯示錯誤(sudo: invalid option -- 'j')是為什麼啊?
    還請多多指教,謝謝

    回覆刪除
    回覆
    1. 哈哈哈抱歉XD
      應該是 sudo make -j 5 KDEB_PKGVERSION=1.任意-文字-於此地 deb-pkg
      我少打上去XD
      位置的話,我看圖片紀錄應該是和 kernel 在同個目錄底下

      刪除
  5. 學長你好~我是逢甲通訊的學弟
    我的版本是4.4.0-66-generic
    我使用sudo apt-get source linux-image-4.4.0-66-generic時都會跑出錯誤訊息
    E: You must put some 'source' URIs in your sources.list
    我去Ubuntu pakage查到需要在sources.list中添加這行
    deb http://security.ubuntu.com/ubuntu xenial-security main
    而我也加上去了
    但還是出現一樣的錯誤訊息...

    回覆刪除
    回覆
    1. 學弟你好
      你要不要在確認一次看看對應的解法與你手上的OS版本是否相同
      根據我目前拿到的key word來搜尋,學弟可能是採用Ubuntu 16.04
      你會不會是指令打錯還是步驟沒有做完全呢XD?

      我有找到類似狀況的,你也可以試試看
      http://askubuntu.com/questions/436247/uris-for-linux-image-3-11-0-15-generic

      刪除

張貼留言

這個網誌中的熱門文章

Raspberry pi 樹莓派系列 :安裝瀏覽器

『如何說出好故事|故事架構介紹|輕鬆做出大師級故事架構』

[Regular Expression]正規表達式教學,使用狀態機輔助說明-基礎篇