## Specfication same as assignment1
## Step
| 步驟 | 說明 |
|:------:|:------:|
|1|加入一個system call entry <br> |
|2| `cd /usr/src/linux-6.10.9/include/linux` <br> 新增header`sudo gedit printfo.h` <br> )
|
|3| 加入system call define`cd /usr/src/linux-6.10.9/kernel` <br> `gedit sys.c`加入header <br><img src="https://hackmd.io/_uploads/Sk1GJBPbkx.png =" width="50%" /><img src="https://hackmd.io/_uploads/H1hzyHwZkg.png =" width="50%" />
|4.1| `cd /usr/src/linux-6.10.9/include/linux` <br>`sudo gedit syscalls.h`加入剛剛自定義好的header **"linux/prinfo.h"**|
|4.2| 往下加入system call linkage <br> |
|5.1| 開始編譯kernel `sudo make -j8` <br> |
|5.2| 安裝剛編譯好的kernel `sudo make install` <br>  |
|5.3| 重開機 <br> |
|6.1| 建立測試檔案 `cd /home` <br> `sudo gedit test2.c` <br> |
|6.2|在user mode端呼叫system call **464**! <br> <img src="https://hackmd.io/_uploads/ryDOJSw-Jx.png " width="70%" />|
|7|運行的結果,兩個不同shell <br><img src="https://hackmd.io/_uploads/BkNKySDbye.png " width="50%" /><img src="https://hackmd.io/_uploads/Sy45krw-Jl.png" width="50%" />|
<div style="page-break-after: always;"></div>
# Challenging part
一開始沒看到有tips,所以直接慢慢地從kernel source code裡面挖掘需要的資訊從`sched.h`, `thread_info.h`,從`task_struct`裡面找到PCB的資訊,在想有什麼方式可以直接取得目前process的資訊,這時候我看到有一個叫做`current`的結構,依照裡面macro的定義,在網路上找了一下這個結構的定義,發現`thread_info`有相依性,但型別是`thread_info`,但是又可以接收task_struct的型別,我就嘗試在`SYSTEM_DEFINE`呼叫看看`current`的型別,一試就成功,再來是處理nice value的轉換,kernel code裡面也有包含轉換`static priority`成`nice值`的macro,也成功解決,之後遇到要把kernel當中的資料複製回user mode,需要有copy_to_user的函示來幫忙檢查權限,我是直接複製指標回去,然後編譯看看,有成功的編譯完成,而後面user mode測試也很順利的解決,沒遇到太多問題。
<div style="page-break-after: always;"></div>
# Reference
[task_struct講解](https://www.cnblogs.com/yungyu16/p/13023982.html)
[task struct mapping 技術](https://hackmd.io/@PIFOPlfSS3W_CehLxS3hBQ/S14tx4MqP)
[copy to user檢查](https://hackmd.io/@sakuraiiii/r1gFubKkF)
[關於linux list_head, list這邊說明得很清楚 : Linux list wrapper](https://hackmd.io/@RinHizakura/HkEuhNwGO)
[nice val](https://deepinout.com/linux-kernel-api/linux-kernel-api-process-scheduling/linux-kernel-api-task_nice.html)
<div style="page-break-after: always;"></div>
# Appendix
### prinfo.h
```c
#include <linux/types.h>
#ifndef PRINTFO_H
#define PRINTFO.H
struct printfo{
long state;
long nice;
pid_t pid;
pid_t parent_pid;
pid_t youngest_child_pid;
unsigned long start_time;
long user_time;
long sys_time;
long uid;
char comm[16];
};
#endif
```
### SYSTEM_DEFINE1
```c
SYSCALL_DEFINE1(print_process_info, struct printfo *, usr_task_info)
{
struct prinfo task_info;
struct prinfo *task_ptr = &task_info;
task_ptr->state = current->__state;
task_ptr->nice = task_nice(current);
task_ptr->pid = current->pid;
task_ptr->parent_pid = current->parent->pid;
if(!list_empty(¤t->children))
task_ptr->youngest_child_pid = list_last_entry(¤t->children, struct task_struct, children)->pid;
else
task_ptr->youngest_child_pid = -1;
task_ptr->start_time = current->start_time;
task_ptr->user_time = current->utime;
task_ptr->sys_time = current->stime;
task_ptr->uid = current->cred->uid.val;
strncpy(task_ptr->comm, current->comm, 16);
if(copy_to_user(usr_task_info, task_ptr, sizeof(struct printfo)))
return -EFAULT;
return 0 ;
}
```
### test2.c
```c
#include <stdio.h>
#include <sys/syscall.h>
#include <unistd.h>
struct printfo{
long state;
long nice;
pid_t pid;
pid_t parent_pid;
pid_t youngest_child_pid;
unsigned long start_time;
long user_time;
long sys_time;
long uid;
char comm[16];
};
int main() {
long res = syscall(464, &user_task);
printf("Syscall return : &ld\n", res);
if(res == 0) {
printf("current task state : %ld\n", user_task.state);
printf("current task nice val : %ld\n", user_task.nice);
printf("current task pid : %d\n", user_task.state);
printf("current task parent pid : %d\n", user_task.state);
printf("current task youngest child pid : %d\n", user_task.state);
printf("current task start time : %ld\n", user_task.state);
printf("current task user time : %ld\n", user_task.state);
printf("current task system time : %ld\n", user_task.state);
printf("current task uid : %ld\n", user_task.state);
printf("current task comm : %s\n", user_task.state);
return 0;
}
printf("Something wrong\n");
exit(1);
}
```