【OS】操作系统-实验一:添加系统调用


操作环境:

  • 主机:MacOS 10.13.3
  • 虚拟机软件:Parallels Desktop
  • Linux:Ubuntu 16.04 Kernal 4.13.0-36-generic

实验要求:

  1. 添加一个系统调用,实现对指定进程的 nice 值的修改或读取功能,并返回进程最新的 nice 值及优先级 prio。建议调用原型为:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    int mysetnice (pid_t pid, int flag, int nicevalue, void_ user * prio, void__ user* nice);
    /*
    参数含义:

    pid:进程 ID.

    flag:若值为 0,表示读取 nice 值;若值为 1,表示修改 nice 值。

    prio、nice:指向进程当前优先级及 nice 值。

    返回值:系统调用成功时返回 0,失败时返回错误码 EFAULT。
    */
  2. 写一个简单的应用程序测试(1) 中添加的系统调用。

  3. 若程序中调用了 Linux 的内核函数,要求深入阅读相关函数源码。

操作步骤:

  1. 编辑./linux-4.14.35/arch/x86/entry/syscalls/syscall_64.tbl,添加 sys_aeonnisetnice 并指定调用号为 666

tbl

  1. 编辑./linux-4.14.35/include/linux/syscalls.h添加服务的原型声明:

sys-h

  1. 编辑./linux-4.14.35/kernel/sys.c添加服务的实现代码:

sys-c

  1. 安装必要的软件:

    1
    2
    $ sudo apt-get install build-essencial
    $ sudo apt-get install libncurses5-dev libssl-dev
  2. 下载内核源代码、解压:

    1
    2
    3
    4
    $ wget https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.14.35.tar.xz
    $ xz -d linux-4.14.35.tar.xz
    $ tar -xvf linux-4.14.35.tar
    $ sudo chmod 777 ./linux-4.14.35
  3. 开始编译内核:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    $ cd ./linux-4.14.35

    $ sudo su
    make menuconfig
    make # 尝试使用 make -j 参数,但是会出现问题,似乎自动注销了
    make modules
    make modules_install
    make install
    update-grub2

mkinstall

  1. 写一个测试程序 testCall.c

testcall

  • 编译 testCall.c
    1
    $ gcc testCall.c -o testCall
  1. 重启系统,进入新内核,运行:
    1
    $ ./testCall

result

  • 接着运行 dmesg 可以看到系统调用中 printk 函数的输出:

dmesg

结果:

  • 成功编译并运行了4.14.35版本的内核。
  • 加入了自己的系统调用,并成功测试运行,成功读写进程的 nice 值

附录:

  1. 系统调用服务的实现代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
SYSCALL_DEFINE5(aeonnisetnice,pid_t,pid,int,flag,int,nicevalue,void __user*,prio,void __user*,nice)
{
struct pid * kpid;
struct task_struct * task;
kpid = find_get_pid(pid);/* 返回pid */
task = pid_task(kpid, PIDTYPE_PID);/* 返回task_struct */
int n;
n = task_nice(task);/* 返回进程当前nice值 */
int p;
p = task_prio(task);
if(flag == 1)
{
set_user_nice(task, nicevalue);/* 修改进程nice值 */

printk("Modified nice:%d\n", nicevalue);

n = task_nice(task);
copy_to_user(nice,&n,sizeof(n));
copy_to_user(prio,&p,sizeof(p));
return 0;
}
else if(flag == 0)
{
printk("nice value is %d\n", n);
printk("priority: %d\n", p);

copy_to_user(nice,&n,sizeof(n));
copy_to_user(prio,&p,sizeof(p));
return 0;
}
return EFAULT;
}
  1. 测试代码 testCall.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#define _GNU_SOURCE
#define _AEONNI_SETNICE_ 666

#include <unistd.h>
#include<sys/syscall.h>
#include<stdio.h>
#include<stdlib.h>
int main(){
pid_t pid;
int nicevalue;
int flag;
int prio = 0;
int nice = 0;
int *p;
int *n;
p = &prio;
n = &nice;
printf("Enter pid:\n");
scanf("%d", &pid);
printf("pid success \nEnter nice:\n");
scanf("%d", &nicevalue);
printf("nice sucess\nEnter flag:\n");
scanf("%d", &flag);
syscall(_AEONNI_SETNICE_, pid, flag, nicevalue, p, n);
printf("Now nice is %d\n,prio is %d\n",nice,prio);
return 0;
}

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×