---
# System prepended metadata

title: AOS assignment3
tags: ['#kernelconfig']

---

## Specfication same as assignment1
## Step
 | 步驟 | 說明 |
|:------:|:------:|
|1|加入一個system call entry <br> ![image](https://hackmd.io/_uploads/HkdAANvW1g.png)![image-1](https://hackmd.io/_uploads/BySgySvZyx.png)|
|2| `cd /usr/src/linux-6.10.9/include/linux` <br> 新增header`sudo gedit printfo.h` <br> ![image-2](https://hackmd.io/_uploads/HJtJkBPZyx.png =500x300))
 |
|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"**![image-9](https://hackmd.io/_uploads/rkuQkHwWkx.png =500x300)|
|4.2| 往下加入system call linkage <br> ![image-5](https://hackmd.io/_uploads/rkMNkBP-yl.png)|
|5.1| 開始編譯kernel `sudo make -j8` <br> ![image-10](https://hackmd.io/_uploads/r134krv-kg.png)|
|5.2| 安裝剛編譯好的kernel `sudo make install` <br> ![image-11](https://hackmd.io/_uploads/HJ18yBw-1e.png =500x300) |
|5.3| 重開機 <br> ![image-12](https://hackmd.io/_uploads/BkT81HwZkg.png)|
|6.1| 建立測試檔案 `cd /home` <br> `sudo gedit test2.c` <br> ![image-13](https://hackmd.io/_uploads/HypD1rvZ1l.png)|
|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(&current->children))
        task_ptr->youngest_child_pid = list_last_entry(&current->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);
}
```