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

操作环境:

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

实验要求:

  1. 添加一个系统调用,实现对指定进程的 nice 值的修改或读取功能,并返回进程最新的 nice 值及优先级 prio。建议调用原型为:
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。
*/
  1. 写一个简单的应用程序测试(1) 中添加的系统调用。

  2. 若程序中调用了 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. 安装必要的软件:
$ sudo apt-get install build-essencial
$ sudo apt-get install libncurses5-dev libssl-dev
  1. 下载内核源代码、解压:
$ 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
  1. 开始编译内核:
$ 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
    $ gcc testCall.c -o testCall
    
  1. 重启系统,进入新内核,运行:
$ ./testCall

result

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

dmesg

结果:

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

附录:

  1. 系统调用服务的实现代码:
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
#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;
}