# OS project - implement system call on Raspbian ###### tags: `project1` Goal: 在linux發行版上新增一個System Call 個人目標: 在raspbian上完成本次作業 選擇raspbian的原因是因為編譯raspbian的時間比編譯完整的kernel核心還要快很多,這是因為raspbian是為了樹梅派設計的作業系統,在算力與功耗有限的環境下並不適合使用完整的Linux,因此raspbian刪除了完整linux的許多功能,這也帶來了建置快速的好處。 畢竟誰也不想編譯了一個晚上結果發現編譯失敗呢~所以就選擇了編譯所需時間極短的raspbian來完成本次作業。 這份筆記包含在QEMU模擬樹梅派、編譯raspbian核心、新增system call以及追蹤system call ---- ## 流程 ### 1. 事前準備 因為樹梅派是arm架構的電腦,所以用virtual box這種虛擬機是無法達成目標的,需要靠像是QEMU這類的emulator才能在intel x64 cpu上執行為arm架構設計的作業系統,另外本次使用的環境是Ubuntu 18.04 所以來安裝QEMU吧 * sudo apt-get install qemu 要編譯raspbian核心有兩種方式,第一種是用QEMU執行大神編譯好的kernel(步驟3的repo有),然後在QEMU模擬的樹梅派上編譯,第二種是在一般的電腦(通常不會是arm架構吧)進行跨平台的cross compile,也就是交叉編譯。 一般情況下,在電腦上交叉編譯的速度會比在QEMU模擬的arm架構的電腦上編譯快的非常多,所以這裡使用的是第二種,交叉編譯。 所以還需要安裝交叉編譯的軟體,因為就如前述,筆電跟樹梅派的架構是不同的。 * sudo apt-get install gcc-arm-linux-gnueabihf ### 2. 下載raspbian source code [github](https://github.com/raspberrypi/linux) ### 3. 大神的設定檔[github](https://github.com/dhruvvyas90/qemu-rpi-kernel) ### 4. 編譯Kernel 把(2)的資料夾放到(3)的tool裡面,執行build-kernel-qemu執行檔,記得要改一下執行檔內容 KERNEL_MAKE_CONFIG=olddefconfig 交叉編譯的時間很快,大概十分鐘以內,這也是我選擇raspbian的原因,因為是給嵌入式系統使用的,不會太複雜。 前述的設定是為了直接使用大神的設定檔,如果不改的話就要手動設定,也就是下圖 其實不一定要用步驟3的repo,自己編譯也可以,但是預設的選項有些不能夠在QEMU上運作,因為QEMU無法真正模擬所有的硬體,所需的知識量暫時超出我的能力範圍,所以就先用別人的設定吧。  ### 5. 啟動QEMU raspberry pi 執行完以後會產生kernel以及dtb檔,把這兩個檔案跟raspbian映像檔放在同個資料夾,然後執行QEMU,指令如下 ```SHELL=1 sudo qemu-system-arm \ -kernel ./qemu-kernel-4.19.50 \ -append "root=/dev/sda2 panic=1 rootfstype=ext4 rw" \ -hda raspbian-buster.img \ -cpu arm1176 -m 256 \ -M versatilepb \ -no-reboot \ -serial stdio \ -dtb versatile-pb.dtb -net nic -net user \ -net tap,ifname=vnet0,script=no,downscript=no ``` 順利的話應該會看到這個畫面  開機完成就會出現以下的畫面  畢竟是在虛擬的硬體上跑,會花滿多時間的,請耐心等待。 ### 6. 如何新增System call 上面展示的是如何編譯raspbian並在QEMU執行,接下來要說明如何增加最簡單的**hello world** System call 新增一個system call要修改三個既有檔案,分別是 * Makefile * arch/arm/tools/syscall.tbl * include/linux/syscalls.h 並且要加入新system call的程式碼以及編譯該程式碼的Makefile 首先在最外圍的資料夾新增一個放置system call程式碼的資料夾並新增程式碼以及Makefile ```SHELL=1 mkdir os_hello cd os_hello touch os_hello.c touch Makefile ``` os_hello.c的內容為 ```SHELL=1 /* os_hello.c */ #include <linux/kernel.h> asmlinkage long sys_os_hello(void){ printk("Hello world! This is OS project 1\n"); return 0; } ``` Makefile的內容為 ```SHELL=1 obj-y := os_hello.o ``` 到上面就完成hello world的system call程式碼了,接下來要讓編譯器知道程式碼的路徑,並讓kernel知道有這個system call。 也就是編輯最外圍資料夾的Makefile。 在最外圍的Makefile這份檔案裡面應該有以下的語句 ```SHELL=968 ... ifeq ($(KBUILD_EXTMOD),) core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/ ``` 這邊是告訴編譯器要去哪裡找程式碼,我們把剛剛的os_hello資料夾直接加在最後面 ```SHELL=968 ... ifeq ($(KBUILD_EXTMOD),) core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/ os_hello/ ``` 第三步是讓kernel知道有這個System call。 找到```arch/arm/tools/syscall.tbl```這份紀錄了system call的table 把新增的system call直接加在最後面就可以了,這邊記得要記住system call的編號,下面的例子編號是400,之後測試的時候要使用。 ```SHELL=413 ... 397 common statx sys_statx 398 common rseq sys_rseq 399 common io_pgetevents sys_io_pgetevents 400 common os_hello sys_os_hello ``` 最後一步是把新增的這個system call放到header file讓一般的程式也可以使用,相信講到標頭檔應該就可以想到是要修改```include/linux/syscalls.h```了。要新增的內容自然就是新加入的system call的prototype,```asmlinkage long sys_os_hello(void);``` 我把prototype加在```Architecture-specific system calls```之前。 ```SHELL=904 ... asmlinkage long sys_rseq(struct rseq __user *rseq, uint32_t rseq_len,int flags, uint32_t sig); asmlinkage long sys_os_hello(void); ``` 以上就完成System call的新增了。 接下來只要重複上面的(4)與(5)步驟,編譯完並執行就可以了。 ### 7. 測試System call 在QEMU上寫一個c程式來呼叫使用剛剛新增的system call。 在QEMU的樹梅派上開啟終端機並新增檔案。 ```SHELL=1 cd Desktop touch hello.c ``` 程式碼長這樣,注意第8行的syscall()的參數為(6)的時候新增的system call編號,這邊是400 ```SHELL=1 #include <linux/kernel.h> #include <sys/syscall.h> #include <unistd.h> #include <stdio.h> int main(void) { long retval = syscall(400); return retval; } ``` 然後編譯並執行 ```SHELL=1 gcc hello.c -o hello ./hello ``` 接著使用linux的dmesg看看kernel的緩衝區有沒有什麼新東西。  看起來是相當的順利!! ### 8. 追蹤System Call 最後來談談如何追蹤一個system call吧! 這裡要使用的工具是strace,使用上相當容易 ```SHELL=1 strace -T ./hello ``` 結果如下  圖中圈起來的部份有寫到0x190,那也就是10進位的400,就是我們在第6步的時候新增的system call的編號囉! ## Reference [QEMU raspbian kernel](https://github.com/dhruvvyas90/qemu-rpi-kernel) [Raspbian source code](https://github.com/raspberrypi/linux)
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up