# OS project - implement system call ###### tags: `project1` ## 指令簡介 * 查看當前kernel 版本 ``` uname -r ``` * 解壓縮 ``` tar -xvf linux-4.17.4.tar.xz -C/usr/src/ ``` `tar` — Tar stores and extracts files from a tape or disk archive. `-x`— extract files from an archive `-v` — requested using the –verbose option, when extracting archives `-f` — file archive; use archive file or device archive 因此 `-xvf` 合在一起代表 解壓縮f 後面的檔案,並印出相關訊息。 `-C `— extract to the directory specified after it.(in this case /usr/src/) 指定解壓縮的位置 ## Makefile ### 好處 1. 簡化編譯時所需要下達的指令。 2. 僅會針對被修改了的檔案進行編譯,其他的 object file 不會被更動,因此可以簡化重新編譯的時間。 3. 最後可以依照相依性來更新 (update) 執行檔。 ### 基本語法 ``` 標的(target): 目標檔1 目標檔2 <tab> gcc -o 欲建立的執行檔 目標檔1 目標檔2 ``` * #代表註解 - <tab> 需要在命令行 (例如 gcc 這個編譯器指令) 的第一個字元; - 標的 (target) 與相依檔案(就是目標檔)之間需以『:』隔開 ## 步驟 1. 由於實做新的system call 相當於在kernel 新增新的指令,因此下載新的kernel來重新編譯 這邊下載的版本為 4-17.4 ``` wget https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.17.4.tar.xz ``` 2. 解壓縮 ``` sudo tar -xvf linux-4.17.4.tar.xz -C/usr/src/ ``` 3. 進到剛才解壓縮的目錄之下 ``` cd /usr/src/linux-4.17.4/ ``` 4. 實做hello 的systemcall 先創個資料夾,把資料都放進去 ``` mkdir hello ``` 實做c code ```c #include <linux/kernel.h> asmlinkage long sys_hello(void) { printk("Hello world\n"); return 0; } ``` 其中`asmlinkage` 是個巨集,當實做c code 時,用來表示**從組合語言到C語言程式碼引數** **是通過stack的傳遞** ,當實做 system call 時,需要在entry.s檔案中用組合語言呼叫,確保其符合C語言的引數傳遞規則,才能用匯編語言正確呼叫它。 5. Make file in hello 在 hello 資料夾中加入Makefile 檔 ``` gedit Makefile ``` 並加入 ``` obj-y := hello.o ``` 這時,資料夾中的檔案有這兩個。 ![](https://i.imgur.com/JHvm0WX.png) 其中 `:=` 會覆蓋變數之前的值 6. Make file in Linux 返回上一層 ``` cd .. ``` 在 Makefile 中加入,如下圖。 ``` core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ hello/ ``` **更正** ![](https://i.imgur.com/ZDJBm3Q.png) 這是為了告訴編譯器,新的system call 的來源,需要編譯hello 中的hello.c 等檔案。 7. 將新的`system call` 加到 `system call table` 中 進到 arch/x86/entry/syscalls/ ``` cd arch/x86/entry/syscalls/ gedit syscall_64.tbl ``` 加入 ``` 548 64 hello sys_hello ``` 格式為 ``` <number> <abi> <name> <entry point> ``` 548 為最後一個指令的序號 547+1 而來,而 64 為64bit的指令,這與實做的虛擬機硬體架構有關,後面兩個分別為檔名與function名稱。 ![](https://i.imgur.com/F8pVW08.png) 8. 將`system call` 加到`sysytem call header file` 中 回到 `linux-4.17.4/` 進到 ``` cd include/linux/ gedit syscalls.h ``` 加入剛實做的function 名稱到最後面。 ``` asmlinkage long sys_hello(void); ``` ![](https://i.imgur.com/lvsRTO1.png) 9. 環境配置 為了完成編譯system call 需要先確認環境的配置 ``` sudo apt-get install gcc sudo apt-get install libncurses5-dev sudo apt-get install bison sudo apt-get install flex sudo apt-get install libssl-dev sudo apt-get install libelf-dev sudo apt-get update sudo apt-get upgrade ``` 建立config 檔案 ``` sudo make menuconfig ``` 10. Make 開始編譯 ``` sudo make -j[n] ``` 其中 [n] 為要使用的CPU核心數,可以加快編譯的速度:)。 ``` sudo make modules_install install ``` ![](https://i.imgur.com/Cc5QneH.png) 編譯完後的hello 內 ![](https://i.imgur.com/qMAbMtu.png) 檢查/boot 底下有沒有我們編譯完的kernel ![](https://i.imgur.com/QZ8fHOQ.png) 11. 重開機,並按下ESC 切換kernel,可按的時間很短暫,我試了快20次才成功 ![](https://i.imgur.com/vQ77eyF.png) 12. 測試程式碼 ```c #include <stdio.h> #include <linux/kernel.h> #include <sys/syscall.h> #include <unistd.h> int main() { long int msg = syscall(548); printf("System call sys_hello returned %ld\n", msg); return 0; } ``` 編譯程式碼 ``` gcc userspace.c ./a.out ``` return 0 代表有執行systemcall ![](https://i.imgur.com/0yM7vtE.png) 詳細顯示 ``` dmesg ``` ![](https://i.imgur.com/wAkj92Q.png) 成功!! ## 錯誤處理 1. 第一次make 出現以下訊息 ``` Makefile:1063: target 'kernel' given more than once in the same rule Makefile:1063: target 'mm' given more than once in the same rule Makefile:1063: target 'fs' given more than once in the same rule Makefile:1063: target 'ipc' given more than once in the same rule Makefile:1063: target 'security' given more than once in the same rule Makefile:1063: target 'crypto' given more than once in the same rule Makefile:1063: target 'block' given more than once in the same rule scripts/kconfig/conf --syncconfig Kconfig *** *** Configuration file ".config" not found! *** *** Please run some configurator (e.g. "make oldconfig" or *** "make menuconfig" or "make xconfig"). *** scripts/kconfig/Makefile:40: recipe for target 'syncconfig' failed make[2]: *** [syncconfig] Error 1 Makefile:528: recipe for target 'syncconfig' failed make[1]: *** [syncconfig] Error 2 make: *** No rule to make target 'include/config/auto.conf', needed by 'include/config/kernel.release'. Stop. make: *** Waiting for unfinished jobs.... ``` ​ 見上方6更正 2. 無法更換kernel, * 解決方法1,開機時狂按ESC ![](https://i.imgur.com/nWijSOL.png) ![](https://i.imgur.com/OCcLZFQ.png) * 方法二,修改grub 檔 ``` sudo gedit /etc/default/grub ``` 將 ``` GRUB_TIMEOUT_STYLE=hidden GRUB_TIMEOUT=0 ``` 改成 ``` GRUB_TIMEOUT_STYLE=menu GRUB_TIMEOUT=60 ``` 最後,更新grub,重開機即可看到選單 ``` sudo update-grub ``` ### 參考資料 [Adding a Hello World System Call to Linux Kernel](https://medium.com/anubhav-shrimal/adding-a-hello-world-system-call-to-linux-kernel-dad32875872) [第二十一章、軟體安裝:原始碼與 Tarball](http://linux.vbird.org/linux_basic/0520source_code_and_tarball.php?fbclid=IwAR2D8npyKgpH98v8e91YlDMd_vsOUR_pgf3cpxGDFfbViL99HhDQjgYnzvs) [Makefile的賦值運算符(=, :=, +=, ?=)](http://dannysun-unknown.blogspot.com/2015/03/makefile.html) [asmlinkage的作用](https://www.itread01.com/p/165670.html)