给Linux增加系统调用

1、前期准备工作

(2)安装 必要软件

sudo apt-get install git fakeroot build-essential ncurses-dev xz-utils libssl-dev bc flex libelf-dev bison

(2)查看当前内核版本 及可以安装的内核版本

查看可以安装的内核版本

apt-cache search linux-source

查看当前内核版本

uname -r

(3)下载内核源码

sudo apt-get install linux-source-5.0.0

 

(4)解压

sudo tar jxvf linux-source-5.0.0.tar.bz2

 

2、实验添加的系统调用功能

(1)添加一个系统调用,实现对指定进程的nice值的修改或读取功能,并返回进程最新的nice值及优先级。建议调用原型是int mysetniec(pid_t pid, int flag, int nicevalue, void_user* prio, void_user* nice);

参数含义:
pid:进程ID
flag:若为0,则表示读取nice的值;若为1,则表示修改nice的值。
nicevalue:为指定的进程设置新的nice。
prio,nice:指向进程的优先级和nice值。
返回值:系统调用成功时返回0;失败时返回错误码EFAULT。

(2)定义你所要添加的系统调用名,然后在linux-source-5.0.0/kernel/创建一个文件,文件名为:mysyscall.c文件的内容为:
(3)若系统调用了Linux的内核函数,要求深入阅读相关的源码。

 

3、实现自己的系统调用服务例程

在linux-source-5.0.0/kernel/sys.c 中添加如下代码(自定义系统调用)

把功能分拆成一个一个小块,我们需要做到的有以下几点:

根据进程号pid找到相应的进程控制块PCB(因为进程控制块中记录了用于描述进程情况及控制进程运行所需要的全部信息,nice值和优先级正是其中的一部分);

根据PCB读取它的nice值和优先级prio;

根据PCB对相应进程的nice值进行修改;

将得到的nice值和优先级prio进行返回。


SYSCALL_DEFINE5(first_compile, pid_t, pid, int, flag, int, nicevalue, void __user *, prio, void __user *, nice){

        int cur_prio, cur_nice;
        struct pid *ppid;
        struct task_struct *pcb;

        ppid = find_get_pid(pid);
        pcb = pid_task(ppid, PIDTYPE_PID);

        if (flag == 1) {

                set_user_nice(pcb, nicevalue);

        }
        else if (flag != 0 {

                return EFAULT;

        }

        cur_prio = task_prio(pcb);
        cur_nice = task_nice(pcb);
        copy_to_user(prio, &cur_prio, sizeof(cur_prio));
        copy_to_user(nice, &cur_nice, sizeof(cur_nice));

        return 0;

}

 

4、分配系统调用号,修改系统调用表

(1)查看系统调用表,并修改

sudo  gedit  /usr/src/linux-source-5.0.0/arch/x86/entry/syscalls/syscall_64.tbl

上图中的4列对应下图:

应用二进制接口分为三种:64、x32和common,即三种不同的调用约定,这里不需考虑太多,三种任意选择一种即可。

系统调用号

应用二进制接口

系统调用名

服务例程入口地址

335

64

first_compile

__x64_sys_first_compile

(2)声明系统调用服务例程

sudo  gedit  /usr/src/linux-source-5.0.0/include/linux/syscalls.h

 

5、开始编译内核

用下面这条命令查漏补缺

sudo apt-get install libncurses5-dev make openssl libssl-dev bison flex

然后定位到,源码在的目录,也就是解压后放的目录

sudo make menuconfig

然后会出现以下界面,根据下面的图片所指的按钮来,通过左右键来确定光标停在选的按钮上,enter键是确定键

如果是要放开 mmap 的内存限制,可以修改如下参数(/ 可以进入查找):

CONFIG_EXPERT = y

CONFIG_X86_PAT = n

CONFIG_STRICT_DEVMEM = n

 

光标移动到 save 处,entry,跟着点击 exit

准备工作做好后,开始编译,耗时最长(大概2小时)
sudo make -j2  2>/home/qhc/error.txt // 使用2个线程进行编译

6安装内核

还是在原来的目录路径下,安装模块

sudo make modules_install

安装内核

sudo make install

 

7使用新内核

(1)创建initrd文件

sudo mkinitramfs -o /boot/initrd.img-5.0.0

(2)在linux开机界面添加 grub 引导界面

修改配置文件

sudo gedit /etc/default/grub 

 

(3)更新grub引导列表

sudo update-grub

 

(4)重启,选择新内核

 

8编写测试 自定义系统调用的程序

(1)编写 test.c 文件,随便放哪

#include <unistd.h>
#include <sys/syscall.h>
#include <stdio.h>

#define _SYSCALL_MYSETNICE_ 335    // 335,刚才添加的系统调用号
#define EFALUT 14

int main() {
    int pid, flag, nicevalue;
    int prev_prio, prev_nice, cur_prio, cur_nice;
    int result;

    printf("Please input variable(pid, flag, nicevalue): ");
    scanf("%d%d%d", &pid, &flag, &nicevalue);
    result = syscall(_SYSCALL_MYSETNICE_, pid, 0, nicevalue, &prev_prio, &prev_nice);
    if (result == EFALUT) {
        printf("ERROR!");
        return 1;
    }
    if (flag == 1) {
        syscall(_SYSCALL_MYSETNICE_, pid, 1, nicevalue, &cur_prio, &cur_nice);
        printf("Original priority is: [%d], original nice is [%d]\n", prev_prio,prev_nice);
        printf("Current priority is : [%d], current nice is [%d]\n", cur_prio,cur_nice);
    }
    else if (flag == 0) {
        printf("Current priority is : [%d], current nice is [%d]\n", prev_prio,prev_nice);
    }
    return 0;

}

(2)利用 gcc 编译 test.c

 

(3)开始测试

 

 

要给Linux增加一个系统调用,首先需要对Linux内核进行修改。具体的步骤如下: 1. 在内核源码中确定添加系统调用的位置。通常可以在`arch/x86/entry/syscalls`目录下找到系统调用表的文件,例如`syscall_64.tbl`。 2. 打开相应的系统调用表文件,添加一行来定义新的系统调用。每行包含系统调用号、系统调用名称和对应的处理函数。系统调用号是一个唯一的整数,用来标识系统调用。例如: ``` 336 common my_new_syscall sys_my_new_syscall ``` 3. 找到对应的处理函数所在的文件,通常在`kernel/sys.c`中。在该文件中添加一个新的函数来处理新的系统调用,函数名与上一步中的处理函数名称一致。在函数中实现具体的功能逻辑。 4. 编译内核,确保新的系统调用被包含在编译过程中。执行适当的编译命令,例如`make`。 5. 重新启动计算机,进入新编译的内核。 6. 在用户空间的程序中调用新的系统调用。通过C程序调用系统调用的实例代码如下: ```c #include <stdio.h> #include <unistd.h> #define __NR_my_new_syscall 336 int my_new_syscall() { return syscall(__NR_my_new_syscall); } int main() { int ret = my_new_syscall(); printf("My new system call returned %d\n", ret); return 0; } ``` 以上是向Linux内核中添加一个新的系统调用的基本过程。当然,具体实现会根据系统版本和内核的不同而有所差异,所以这只是一个大致的指导,具体操作还需参考内核版本和相应的文档。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值