← 文章归档

lab2-编译内核并添加系统调用

文章目录 3 节

在开始之前,请现配置好基本的环境,请你先完成下面博客中的qemu和busybox部分

编译x86_64 linux并运行在qemu上

因为内核需要添加系统调用,我们需要重新编译。

本实验均在ubuntu 22.04下进行,编译的内核版本是5.19(低版本内核会在添加系统调用时略有不同)。

添加系统调用

linux-5.19/arch/x86/entry/syscalls/syscall_64.tbl

image-20230602230645731

添加

335	64	mysetnice		sys_mysetnice

linux-5.19/include/linux/syscalls.h

image-20230602231000337

添加

asmlinkage long sys_mysetnice(pid_t pid, int flag, int nicevaluse, void __user* prio, void __user* nice);

linux-5.19/kernel/sys.c

image-20230602231154502

在最后一个#endif前加上下面的代码

// 置于sys.c的最末端(在‘#endif’之前
SYSCALL_DEFINE5(mysetnice, 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;
    int res;

    // 通过进程PID号找到进程的PID结构体,如果ppid为空指针则代表不存在与进程号与pid相同的进程,此时返回EFAULT(
    // 我编译的时候这个if判断并没有加进去,想做出上述判断的可以将注释删去,就逻辑本身而言没有问题-_-
    // 但我无法保证最后是否会出问题,因为我没有自己尝试过
    ppid = find_get_pid(pid);
    /*
    if (ppid == NULL)
        return EFAULT;
    */

    // 通过进程的PID结构体,找到与之对应的进程控制块
    pcb = pid_task(ppid, PIDTYPE_PID);

    // 如果flag=1则修改进程的nice值为nicevalue
    if (flag == 1) {
    set_user_nice(pcb, nicevalue);
    }  // flag既不为1也不为0的时候,即flag出错,此时返回EFAULT
    else if (flag != 0) {
    return EFAULT;
    }

    // 获取进程当前的最新nice值和prio值
    cur_prio = task_prio(pcb);
    cur_nice = task_nice(pcb);

    // 由于系统调用是在内核态下运行的,所有数据均为内核空间的数据,
    // 利用copy_to_user()函数将内核空间的数据复制到用户空间
    res = copy_to_user(prio, &cur_prio, sizeof(cur_prio));
    res = copy_to_user(nice, &cur_nice, sizeof(cur_nice));

    return 0;
}

编译内核

内核的编译步骤与编译x86_64 linux并运行在qemu上的编译步骤相同,不予介绍。

测试添加的系统调用

qemu请务必使用带动态链接库的根文件系统

$ sudo mount rootfs-lib.img rootfs-lib
$ cd rootfs-lib
$ sudo vim sys-demo.c

内容如下:

#include "unistd.h"
#include "sys/syscall.h"
#include "stdio.h"
#define _SYSCALL_MYSETNICE_ 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;
}
$ sudo gcc sys-demo.c -o sys-demo
$ cd ..
$ qemu-system-x86_64 -kernel linux-5.19/arch/x86/boot/bzImage -boot c -m 2048M -hda rootfs-lib.img -append "root=/dev/sda rw console=ttyS0,115200 acpi=off nokaslr" -serial stdio -display none

启动qemu之后启动sys-demo即可

image-20230602232324866