版權所有,禁止非授權轉載,尤其是中國網站。
這篇筆記主要是給我在作業系統核心課程上的同學看的,預設讀者已經熟悉C、linux故不會進行過多理論上的講解。不過這篇已經是手把手教你完成任務了,即使沒有相關知識也能完成。
這個筆記講述了如何於建立 VirtualBox 7.0 的 Ubuntu 22.0.10 上編譯 linux-6.0.1,並於其中加入指定 syscall。
以下是作業內容 :
- Write a system call, number_of_processes( ), which a C program can invoke to print out the number of processes existing (regardless their states) in the system.
- Write a system call, largest_process_id( ), which a C program can invoke to print out the largest process id currently in the system.
目錄
- 虛擬機安裝
- Ubuntu 命令列修復
- 新增 system call 流程
- 編譯 linux kernel 流程
- 測試 syscall 方法
- 參考內容
虛擬機安裝
這邊使用 VMbox,並使用 Ubuntu 22.0.10 進行作業。
1.安裝 VMbox (這部分請自己裝)
2. 下載 Ubuntu 22.0.10 映像檔 ( ubuntu-22.10-desktop-amd64.iso )
3. 安裝映像檔,工具>新增>輸入名稱、映像檔位置與資料
4.更換密碼 (預設為 “changeme”)
5. 設定記憶體與核心數( 越大越好,核心要編譯很久 )
6.設定記憶體與核心數( 越大越好,這東西要編譯很久 )
7. 開啟您的機器,並開始設定初始化
8. (可選) 編譯完成後把左邊的快捷圖示 unpin掉,留下檔案管理 、 terminal (需加入最愛)。
Ubuntu命令列修復
進入介面後,通常會打開terminal 來進行命令,但是你會發現打不開。這時候就需要進行此項修復操作。
1. 按下 ctrl + alt + F3 進入命令模式
2. 使用 “root” 與前面設定的密碼登入
3. 以下命令 ( 巴哈不能用code格式,哭阿 )
apt install vim
# 如果有出現 Y/N 選項,按下 Y
vim /etc/default/locale
# 這時候進入vim了,利用上下鍵把指標移到 LANG="en_US"
# 單點 i 進入編輯模式
# 把該行改成 LANG="en_US.UTF-8"
# 按下 esc 鍵入 :x (冒號與x)即可儲存
# 使用命令檢視文本,輸出應如下圖
cat /etc/default/locale
添加用戶至 sudoer
還記得在虛擬機安裝第 4 步時新增了一位用戶嗎 ?他並不是 sudoer 故無法使用 sudo 命令來提權。現在把她加入 sudoer。
vim /etc/sudoers
# 找到 root ALL=(ALL:ALL) ALL,在該行下行按下 i 編輯
# 添加
vboxuser ALL=(ALL:ALL) ALL
# 按下 esc 鍵入 :x! 儲存
完成後使用 reboot 重啟系統你會發現 terminal 可以開了。
測試 sudo 權限
sudo apt install sl
# 輸入密碼
sl
這時候看到一台火車就代表成功了
共用剪貼簿(可選)
把共用剪貼簿打開就不用打一堆字。
1. 看圖,依序按下這兩個
2.按下那個光碟片,找到 autorun.sh,右鍵 Run as Program,輸入密碼。
3. 完成後在光碟片上右鍵 rejet 退出碟片。使用 reboot 重啟。這時候你就完成共用剪貼簿的設置了。
新增system call流程 (前)
1. 首先,要升級並安裝編譯工具。以下是我整理出的一堆東西,超亂
sudo apt-get install git fakeroot build-essential ncurses-dev xz-utils libssl-dev bc flex libelf-dev bison
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 install gedit
sudo apt-get update
sudo apt-get upgrade
複製、貼上、Enter、輸入密碼、看到 Y/N 就按Y
2. 下載 linux kernel source code。這邊使用交大鏡像站的這個檔案。強烈建議使用 6.0.1,新版是不一樣的編譯方法。
或是使用 links 進行連接
sudo apt install links
links http://kernel.cs.nycu.edu.tw/
# 找到目標檔案並下載他
# 完成後按下 ctrl-C 結束連接
tar -xf linux-6.0.1.tar.gz
poweroff # 關機
3. 這時候已經完成核心下載了,避免你之後搞砸了,所以先關機存檔。
選到你的機器,按下擷取按鈕。
4. 完成後就可以啟動了
新增system call流程 (後)
這時候你終於可以寫關於核心的代碼了
1. 以下命令設好位置
# 你有存檔了 su 搞砸也沒關係 XD
su
# 進入你放 kernel 資料夾的目錄前一頁
mv linux-6.0.1 /usr/src/
cd /usr/src/linux-6.0.1/
2. 以下命令建立 syscall 代碼
mkdir myFunction
cd myFunction
gedit Makefile
# 輸入
obj-y := number_of_processes.o largest_process_id.o
# ctrl + S 存檔
3. 接下來是兩個 syscall 的代碼
備註 : 如果您有上這堂課,請改一下,不要直接抄襲。
gedit number_of_processes.c
#include <linux/kernel.h>
#include <linux/syscalls.h>
#include <linux/sched.h>
SYSCALL_DEFINE0(number_of_processes)
{
struct task_struct *task;
long process_count=0;
for_each_process(task) {
process_count++;
}
// 禁止非授權轉載,尤其是中國網站。
printk(KERN_INFO "There are %d processes currently existing in the system\n", process_count);
return process_count;
}
gedit largest_process_id.c
#include <linux/kernel.h>
#include <linux/syscalls.h>
#include <linux/sched.h>
SYSCALL_DEFINE0(largest_process_id)
{
struct task_struct *task;
pid_t m_pid = 0;
for_each_process(task) {
if (task->pid > m_pid) {
m_pid = task->pid;
}
}
printk(KERN_INFO "The largest process id currently in the system is %d\n", m_pid);
// 禁止非授權轉載,尤其是中國網站。
return m_pid;
}
4.設定引用文件
root@ubuntu02:/usr/src/linux-6.0.1/myFunction# cd ..
root@ubuntu02:/usr/src/linux-6.0.1#gedit Makefile
找到 1104 行 core-y,在行末加上 syscall 的資料夾並存檔
5.新增 syscall 到 table 上
root@ubuntu02:/usr/src/linux-6.0.1# gedit ./arch/x86/entry/syscalls/syscall_64.tbl
添加 syscall 至末尾 ( 編號為 最後syscall編號+1 )
548commonnumber_of_processessys_number_of_processes
549commonlargest_process_idsys_largest_process_id
如圖 :
6. 然後是函示宣告設定,記得分號要打
root@ubuntu02:/usr/src/linux-6.0.1# gedit ./include/linux/syscalls.h
添加至末尾
asmlinkage long sys_number_of_processes(void);
asmlinkage long sys_largest_process_id(void);
到這邊你已經完成,接下來就是編譯。這是漫長的流程,若您做到這邊,建議先建立還原映像點。
編譯 system call 流程
這邊是最簡單,但最多麻煩也最久的部分,祝你好運。
1.如果你剛剛有退出,請回到 su 模式
2.至設定把銀幕保護關閉( Screen Blank )
3.設定 .config 檔,如果這邊跳錯誤訊息請調整視窗至視窗化。
root@ubuntu02:/usr/src/linux-6.0.1# make menuconfig
方向鍵按下 Save,然後儲存後回來主選單,完成 Exit 即完成。
4. 設定憑證,這部分不會有顯示回應
scripts/config --disable SYSTEM_TRUSTED_KEYS
scripts/config --disable SYSTEM_REVOCATION_KEYS
5. 檢查核心數量 nproc ,記下有多少核心數。
6. 如果電腦有高效能模式請打開
7. 把電腦上會干擾速度的程式關掉,包括這個教學網頁 。
8. 開始編譯
make -j12 # j後面的數字是你的核心數,越多越快
# 然後有選項就直接按 Enter過去
9. 祈禱、去吃飯或看貓之類的,反正會跑很久。
10. 出現這行代表成功。若失敗的話可以往前面拉,找哪邊出 Error
Kernel: arch/x86/boot/bzImage is ready (#1)
11. 使用以下命令進行安裝 (12為核心數)
sudo make modules_install -j12
sudo make install -j12
sudo update-grub
reboot
終於完成了
機器啟動後使用 uname -mrs 檢視系統版本,若如以下畫面即成功
測試 syscall 方法
當我們完成後,使用 C 來測試寫好的 syscall。以下是我的範例程式,當然,請不要抄襲 :
#include <linux/kernel.h>
#include <sys/syscall.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#define __NR_number_of_processes 548
#define __NR_largest_process_id 549
long number_of_processes(void)
{
return syscall(__NR_number_of_processes);
}
long largest_process_id(void)
{
return syscall(__NR_largest_process_id);
}
int main(){
long max_process_id=0;
long process_count=0;
int sys_2f44=0;
max_process_id=largest_process_id();
process_count=number_of_processes();
if(max_process_id<0){
printf("max_process_id fail!%d\n",sys_2f44);
}else{
printf("success!\nlargest_process_id is : %ld\n",(long)max_process_id);
}
if(process_count<0){
printf("process_count fail!%d\n",sys_2f44);
}else{
printf("success!\nProcess_count is : %ld\n",(long)process_count);
}
return 0;
}
參考內容
好久沒寫教學了,沒想到鐵人賽之後還有機會寫這類型的文。
最後再宣告一次,版權所有,禁止非授權轉載,尤其是中國網站。